diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000000..7644b41f49 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,13 @@ +Copyright 1999-2011 Alibaba Group. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..15c1e54d4d --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 1999-2101 Alibaba Group. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml new file mode 100644 index 0000000000..d8179ba862 --- /dev/null +++ b/dubbo-cluster/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-cluster + jar + Dubbo Cluster Module + The cluster module of dubbo project + + + com.alibaba + dubbo-rpc + ${project.parent.version} + + + org.apache.bsf + bsf-api + provided + true + + + \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java new file mode 100644 index 0000000000..b39ecea890 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.support.FailoverCluster; + +/** + * Cluster. (SPI, Singleton, ThreadSafe) + * + * Cluster + * Fault-Tolerant + * + * @author william.liangf + */ +@Extension(FailoverCluster.NAME) +public interface Cluster { + + /** + * Merge the directory invokers to a virtual invoker. + * + * @param + * @param directory + * @return + * @throws RpcException + */ + @Adaptive + Invoker merge(Directory directory) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Directory.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Directory.java new file mode 100644 index 0000000000..10bacd8c07 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Directory.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster; + +import java.util.List; + +import com.alibaba.dubbo.common.Node; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * Directory. (SPI, Singleton, ThreadSafe) + * + * Directory Service + * + * @see com.alibaba.dubbo.rpc.cluster.Cluster#merge(Directory) + * @author william.liangf + */ +public interface Directory extends Node { + + /** + * get service type. + * + * @return service type. + */ + Class getInterface(); + + /** + * list invokers. + * + * @return invokers + */ + List> list(Invocation invocation) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/LoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/LoadBalance.java new file mode 100644 index 0000000000..603cfe7617 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/LoadBalance.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster; + +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance; + +/** + * LoadBalance. (SPI, Singleton, ThreadSafe) + * + * Load-Balancing + * + * @see com.alibaba.dubbo.rpc.cluster.Cluster#merge(Directory) + * @author qian.lei + * @author william.liangf + */ +@Extension(RandomLoadBalance.NAME) +public interface LoadBalance { + + /** + * select one invoker in list. + * + * @param invokers invokers. + * @param invocation invocation. + * @return selected invoker. + */ + Invoker select(List> invokers, Invocation invocation) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java new file mode 100644 index 0000000000..9480414e6b --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster; + +import java.util.List; + +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * Router. + * + * @author chao.liuc + */ +public interface Router { + + /** + * route. + * + * @param invokers + * @param invocation + * @return + * @throws RpcException + */ + List> route(List> invokers, Invocation invocation) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/RouterFactory.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/RouterFactory.java new file mode 100644 index 0000000000..0fe4949912 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/RouterFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * RouterFactory. (SPI, Singleton, ThreadSafe) + * + * @author chao.liuc + */ +@Extension +public interface RouterFactory { + + /** + * Create router. + * + * @param url + * @return + */ + @Adaptive("protocol") + Router getRouter(URL url); + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/directory/StaticDirectory.java new file mode 100644 index 0000000000..d7dd7b0b8b --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/directory/StaticDirectory.java @@ -0,0 +1,84 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.directory; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Router; +import com.alibaba.dubbo.rpc.cluster.support.AbstractDirectory; + +/** + * StaticDirectory + * + * @author william.liangf + */ +public class StaticDirectory extends AbstractDirectory { + + private final List> invokers; + + private static final List> EMPTY_INVOKERLIST = new ArrayList>(); + + public StaticDirectory(List> invokers){ + this(null, invokers, null); + } + + public StaticDirectory(List> invokers, List routers){ + this(null, invokers, routers); + } + + public StaticDirectory(URL url, List> invokers) { + this(url, invokers, null); + } + + public StaticDirectory(URL url, List> invokers, List routers) { + super(url == null && invokers != null && invokers.size() > 0 ? invokers.get(0).getUrl() : url, routers); + if (invokers == null || invokers.size() == 0) + throw new IllegalArgumentException("invokers == null"); + this.invokers = invokers; + } + + public Class getInterface() { + return invokers.get(0).getInterface(); + } + + public boolean isAvailable() { + for (Invoker invoker : invokers) { + if (invoker.isAvailable()) { + return true; + } + } + return false; + } + + public void destroy() { + for (Invoker invoker : invokers) { + invoker.destroy(); + } + invokers.clear(); + } + + @Override + protected List> doList(Invocation invocation) throws RpcException { + + return invokers; + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java new file mode 100644 index 0000000000..ff62a6c3ff --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.loadbalance; + +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * AbstractLoadBalance + * + * @author william.liangf + */ +public abstract class AbstractLoadBalance implements LoadBalance { + + public Invoker select(List> invokers, Invocation invocation) { + if (invokers == null || invokers.size() == 0) + return null; + if (invokers.size() == 1) + return invokers.get(0); + return doSelect(invokers, invocation); + } + + protected abstract Invoker doSelect(List> invokers, Invocation invocation); + + protected int getWeight(Invoker invoker, Invocation invocation) { + return invoker.getUrl().getMethodIntParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java new file mode 100644 index 0000000000..87c053b0f8 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java @@ -0,0 +1,86 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.loadbalance; + +import java.util.List; +import java.util.Random; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcStatus; +import com.alibaba.dubbo.rpc.Invocation; + +/** + * LeastActiveLoadBalance + * + * @author william.liangf + */ +@Extension(LeastActiveLoadBalance.NAME) +public class LeastActiveLoadBalance extends AbstractLoadBalance { + public static final String NAME = "leastactive"; + + private final Random random = new Random(); + + protected Invoker doSelect(List> invokers, Invocation invocation) { + int length = invokers.size(); // 总个数 + int leastActive = -1; // 最小的活跃数 + int leastCount = 0; // 相同最小活跃数的个数 + int[] leastIndexs = new int[length]; // 相同最小活跃数的下标 + int totalWeight = 0; // 总权重 + int firstWeight = 0; // 第一个权重,用于于计算是否相同 + boolean sameWeight = true; // 是否所有权重相同 + for (int i = 0; i < length; i++) { + Invoker invoker = invokers.get(i); + int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // 活跃数 + int weight = invoker.getUrl().getMethodIntParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // 权重 + if (leastActive == -1 || active < leastActive) { // 发现更小的活跃数,重新开始 + leastActive = active; // 记录最小活跃数 + leastCount = 1; // 重新统计相同最小活跃数的个数 + leastIndexs[0] = i; // 重新记录最小活跃数下标 + totalWeight = weight; // 重新累计总权重 + firstWeight = weight; // 记录第一个权重 + sameWeight = true; // 还原权重相同标识 + } else if (active == leastActive) { // 累计相同最小的活跃数 + leastIndexs[leastCount ++] = i; // 累计相同最小活跃数下标 + totalWeight += weight; // 累计总权重 + // 判断所有权重是否一样 + if (sameWeight && i > 0 + && weight != firstWeight) { + sameWeight = false; + } + } + } + // assert(leastCount > 0) + if (leastCount == 1) { + // 如果只有一个最小则直接返回 + return invokers.get(leastIndexs[0]); + } + if (! sameWeight && totalWeight > 0) { + // 如果权重不相同且权重大于0则按总权重数随机 + int offsetWeight = random.nextInt(totalWeight); + // 并确定随机值落在哪个片断上 + for (int i = 0; i < leastCount; i++) { + int leastIndex = leastIndexs[i]; + offsetWeight -= getWeight(invokers.get(leastIndex), invocation); + if (offsetWeight <= 0) + return invokers.get(leastIndex); + } + } + // 如果权重相同或权重为0则均等随机 + return invokers.get(leastIndexs[random.nextInt(leastCount)]); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceAdptive.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceAdptive.java new file mode 100644 index 0000000000..9e29dff6a9 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceAdptive.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.loadbalance; + +import java.util.List; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * LoadBalanceAdptive + * + * @author ding.lid + * @author william.liangf + */ +@Adaptive +public class LoadBalanceAdptive implements LoadBalance { + public Invoker select(List> invokers, Invocation invocation) throws RpcException { + if (invokers == null || invokers.size() == 0) { + return null; + } + URL url = invokers.get(0).getUrl(); + String method = invocation.getMethodName(); + String name; + if (method == null || method.length() == 0) { + name = url.getParameter(Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE); + } else { + name = url.getMethodParameter(method, Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE); + } + LoadBalance loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(name); + return loadbalance.select(invokers, invocation); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java new file mode 100644 index 0000000000..a86c5f7210 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java @@ -0,0 +1,66 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.loadbalance; + +import java.util.List; +import java.util.Random; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Invocation; + +/** + * random load balance. + * + * @author qianlei + * @author william.liangf + */ +@Extension(RandomLoadBalance.NAME) +public class RandomLoadBalance extends AbstractLoadBalance { + public static final String NAME = "random"; + + private final Random random = new Random(); + + protected Invoker doSelect(List> invokers, Invocation invocation) { + int length = invokers.size(); // 总个数 + int totalWeight = 0; // 总权重 + boolean sameWeight = true; // 权重是否都一样 + for (int i = 0; i < length; i++) { + // 获取权重 + int weight = getWeight(invokers.get(i), invocation); + // 累计总权重 + totalWeight += weight; + // 判断所有权重是否一样 + if (sameWeight && i > 0 + && weight != getWeight(invokers.get(i - 1), invocation)) { + sameWeight = false; + } + } + if (!sameWeight && totalWeight > 0) { + // 如果权重不相同且权重大于0则按总权重数随机 + int offset = random.nextInt(totalWeight); + // 并确定随机值落在哪个片断上 + for (int i = 0; i < length; i++) { + offset -= getWeight(invokers.get(i), invocation); + if (offset < 0) { + return invokers.get(i); + } + } + } + // 如果权重相同或权重为0则均等随机 + return invokers.get(random.nextInt(length)); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java new file mode 100644 index 0000000000..a8aaec6841 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.loadbalance; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.AtomicPositiveInteger; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Invocation; + +/** + * Round robin load balance. + * + * @author qian.lei + * @author william.liangf + */ +@Extension(RoundRobinLoadBalance.NAME) +public class RoundRobinLoadBalance extends AbstractLoadBalance { + public static final String NAME = "roundrobin"; + + private final ConcurrentMap sequences = new ConcurrentHashMap(); + + protected Invoker doSelect(List> invokers, Invocation invocation) { + String key = invokers.get(0).getInterface().getName() + "." + invocation.getMethodName();// + System.identityHashCode(invokers); + AtomicPositiveInteger sequence = sequences.get(key); + if (sequence == null) { + sequences.putIfAbsent(key, new AtomicPositiveInteger()); + sequence = sequences.get(key); + } + // 取模轮循 + return invokers.get(sequence.getAndIncrement() % invokers.size()); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/FileRouterFactory.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/FileRouterFactory.java new file mode 100644 index 0000000000..86e14b2a7f --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/FileRouterFactory.java @@ -0,0 +1,62 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.router; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.IOUtils; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.cluster.Router; +import com.alibaba.dubbo.rpc.cluster.RouterFactory; + +@Extension(FileRouterFactory.NAME) +public class FileRouterFactory implements RouterFactory { + + public static final String NAME = "file"; + + private RouterFactory routerFactory; + + public void setRouterFactory(RouterFactory routerFactory) { + this.routerFactory = routerFactory; + } + + public Router getRouter(URL url) { + try { + // File URL 转换成 其它Route URL,然后Load + // file:///d:/path/to/route.js?router=script ==> script:///d:/path/to/route.js?type=js&rule= + String protocol = url.getParameter(RpcConstants.ROUTER_KEY, ScriptRouterFactory.NAME); // 将原类型转为协议 + String type = null; // 使用文件后缀做为类型 + String path = url.getPath(); + if (path != null) { + int i = path.lastIndexOf('.'); + if (i > 0) { + type = path.substring(i + 1); + } + } + String rule = IOUtils.read(new FileReader(new File(url.getAbsolutePath()))); + URL script = url.setProtocol(protocol).addParameter(RpcConstants.TYPE_KEY, type).addParameterAndEncoded(RpcConstants.RULE_KEY, rule); + + return routerFactory.getRouter(script); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouter.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouter.java new file mode 100644 index 0000000000..8156b80604 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouter.java @@ -0,0 +1,107 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.router; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +import org.jboss.netty.util.internal.ConcurrentHashMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Router; + +/** + * ScriptRouter + * + * @author william.liangf + */ +public class ScriptRouter implements Router { + + private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class); + + private static final Map engines = new ConcurrentHashMap(); + + private final ScriptEngine engine; + + private final String rule; + + public ScriptRouter(URL url) { + String type = url.getParameter(RpcConstants.TYPE_KEY); + String rule = url.getParameterAndDecoded(RpcConstants.RULE_KEY); + if (type == null || type.length() == 0){ + type = RpcConstants.DEFAULT_SCRIPT_TYPE_KEY; + } + if (rule == null || rule.length() == 0){ + throw new IllegalStateException(new IllegalStateException("route rule can not be empty. rule:" + rule)); + } + ScriptEngine engine = engines.get(type); + if (engine == null){ + engine = new ScriptEngineManager().getEngineByName(type); + if (engine == null) { + throw new IllegalStateException(new IllegalStateException("Unsupported route rule type: " + type + ", rule: " + rule)); + } + engines.put(type, engine); + } + this.engine = engine; + this.rule = rule; + } + + @SuppressWarnings("unchecked") + public List> route(List> invokers, Invocation invocation) throws RpcException { + try { + List> invokersCopy = new ArrayList>(invokers); + Compilable compilable = (Compilable) engine; + Bindings bindings = engine.createBindings(); + bindings.put("invokers", invokersCopy); + bindings.put("invocation", invocation); + bindings.put("context", RpcContext.getContext()); + CompiledScript function = compilable.compile(rule); + Object obj = function.eval(bindings); + if (obj instanceof Invoker[]) { + invokersCopy = Arrays.asList((Invoker[]) obj); + } else if (obj instanceof Object[]) { + invokersCopy = new ArrayList>(); + for (Object inv : (Object[]) obj) { + invokersCopy.add((Invoker)inv); + } + } else { + invokersCopy = (List>) obj; + } + return invokersCopy; + } catch (ScriptException e) { + //fail then ignore rule .invokers. + logger.error("route error , rule has been ignored .rule :"+ rule + ",invocation:" + invocation + ",url :"+(RpcContext.getContext().getInvoker() == null ? "" : RpcContext.getContext().getInvoker().getUrl()), e); + return invokers; + } + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouterFactory.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouterFactory.java new file mode 100644 index 0000000000..43edc39e34 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouterFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.router; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.cluster.Router; +import com.alibaba.dubbo.rpc.cluster.RouterFactory; + +/** + * ScriptRouterFactory + * + * Script Router Factory用到的URL形如: + *
    + *
  1. script://registyAddress?type=js&rule=xxxx + *
  2. script:///path/to/routerfile.js?type=js&rule=xxxx + *
  3. script://D:\path\to\routerfile.js?type=js&rule=xxxx + *
  4. script://C:/path/to/routerfile.js?type=js&rule=xxxx + *
+ * URL的Host一段包含的是Script Router内容的来源,Registry、File etc + * + * @author william.liangf + */ +@Extension(ScriptRouterFactory.NAME) +public class ScriptRouterFactory implements RouterFactory { + + public static final String NAME = "script"; + + public Router getRouter(URL url) { + return new ScriptRouter(url); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvoker.java new file mode 100644 index 0000000000..6cf0b4669b --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvoker.java @@ -0,0 +1,240 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * AbstractRpcRouter + * + * @author william.liangf + * @author chao.liuc + */ +public abstract class AbstractClusterInvoker implements Invoker { + + private static final Logger logger = LoggerFactory + .getLogger(AbstractClusterInvoker.class); + protected final Directory directory; + + protected final boolean availablecheck; + + private volatile boolean destroyed = false; + + private volatile Invoker stickyInvoker = null; + + + public AbstractClusterInvoker(Directory directory) { + this(directory, directory.getUrl()); + } + public AbstractClusterInvoker(Directory directory, URL url) { + if (directory == null) + throw new IllegalArgumentException("service directory == null"); + + this.directory = directory ; + this.availablecheck = url.getBooleanParameter(RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY, RpcConstants.DEFAULT_CLUSTER_AVAILABLE_CHECK) ; + } + + public Class getInterface() { + return directory.getInterface(); + } + + public URL getUrl() { + return directory.getUrl(); + } + + public boolean isAvailable() { + Invoker invoker = stickyInvoker; + if (invoker != null) { + return invoker.isAvailable(); + } + return directory.isAvailable(); + } + + public void destroy() { + directory.destroy(); + destroyed = true; + } + + /** + * 使用loadbalance选择invoker.
+ * a)先lb选择,如果在selected列表中 或者 不可用且做检验时,进入下一步(重选),否则直接返回
+ * b)重选验证规则:selected > available .保证重选出的结果尽量不在select中,并且是可用的 + * + * @param availablecheck 如果设置true,在选择的时候先选invoker.available == true + * @param selected 已选过的invoker.注意:输入保证不重复 + * + */ + protected Invoker select(LoadBalance loadbalance, Invocation invocation, List> invokers, List> selected) throws RpcException { + if (invokers == null || invokers.size() == 0) + return null; + String methodName = invocation == null ? "" : invocation.getMethodName(); + + boolean sticky = invokers.get(0).getUrl().getMethodBooleanParameter(methodName,RpcConstants.CLUSTER_STICKY_KEY, RpcConstants.DEFAULT_CLUSTER_STICKY) ; + { + //ignore overloaded method + if ( stickyInvoker != null && !invokers.contains(stickyInvoker) ){ + stickyInvoker = null; + } + //ignore cucurrent problem + if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))){ + if (availablecheck && stickyInvoker.isAvailable()){ + return stickyInvoker; + } + } + } + Invoker invoker = doselect(loadbalance, invocation, invokers, selected); + + if (sticky){ + stickyInvoker = invoker; + } + return invoker; + } + + private Invoker doselect(LoadBalance loadbalance, Invocation invocation, List> invokers, List> selected) throws RpcException { + if (invokers == null || invokers.size() == 0) + return null; + if (invokers.size() == 1) + return invokers.get(0); + // 如果只有两个invoker,退化成轮循 + if (invokers.size() == 2 && selected != null && selected.size() > 0) { + return selected.get(0) == invokers.get(0) ? invokers.get(1) : invokers.get(0); + } + Invoker invoker = loadbalance.select(invokers, invocation); + + //如果 selected中包含(优先判断) 或者 不可用&&availablecheck=true 则重试. + if( (selected != null && selected.contains(invoker)) + ||(!invoker.isAvailable() && getUrl()!=null && availablecheck)){ + try{ + Invoker rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck); + if(rinvoker != null){ + invoker = rinvoker; + }else{ + //看下第一次选的位置,如果不是最后,选+1位置. + int index = invokers.indexOf(invoker); + try{ + //最后在避免碰撞 + invoker = index reselect(LoadBalance loadbalance,Invocation invocation, + List> invokers, List> selected ,boolean availablecheck) + throws RpcException { + + //预先分配一个,这个列表是一定会用到的. + List> reselectInvokers = new ArrayList>(invokers.size()>1?(invokers.size()-1):invokers.size()); + + //先从非select中选 + if( availablecheck ){ //选isAvailable 的非select + for(Invoker invoker : invokers){ + if(invoker.isAvailable()){ + if(selected ==null || !selected.contains(invoker)){ + reselectInvokers.add(invoker); + } + } + } + if(reselectInvokers.size()>0){ + return loadbalance.select(reselectInvokers, invocation); + } + }else{ //选全部非select + for(Invoker invoker : invokers){ + if(selected ==null || !selected.contains(invoker)){ + reselectInvokers.add(invoker); + } + } + if(reselectInvokers.size()>0){ + return loadbalance.select(reselectInvokers, invocation); + } + } + //最后从select中选可用的. + { + if(selected != null){ + for(Invoker invoker : selected){ + if((invoker.isAvailable()) //优先选available + && !reselectInvokers.contains(invoker)){ + reselectInvokers.add(invoker); + } + } + } + if(reselectInvokers.size()>0){ + return loadbalance.select(reselectInvokers, invocation); + } + } + return null; + } + + public Result invoke(final Invocation invocation) throws RpcException { + + if(destroyed){ + throw new RpcException("Rpc invoker for " + getInterface() + " on consumer " + NetUtils.getLocalHost() + + " use dubbo version " + Version.getVersion() + + " is not destroyed! Can not invoke any more."); + } + + LoadBalance loadbalance; + + List> invokers = directory.list(invocation); + if (invokers != null && invokers.size() > 0) { + loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl() + .getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE)); + } else { + loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE); + } + return doInvoke(invocation, invokers, loadbalance); + } + + @Override + public String toString() { + return getInterface() + " -> " + getUrl().toString(); + } + + protected abstract Result doInvoke(Invocation invocation, List> invokers, + LoadBalance loadbalance) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AbstractDirectory.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AbstractDirectory.java new file mode 100644 index 0000000000..99d2f5b0a4 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AbstractDirectory.java @@ -0,0 +1,87 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.Router; +import com.alibaba.dubbo.rpc.cluster.RouterFactory; + +/** + * 增加router的Directory + * @author chao.liuc + */ +public abstract class AbstractDirectory implements Directory { + + private final URL url ; + private Boolean destroyed = false; + + private List routers = new ArrayList(); + + public AbstractDirectory(URL url) { + this(url, null); + } + + public AbstractDirectory(URL url, List routers) { + if (url == null) + throw new IllegalArgumentException("url == null"); + if (routers == null){ + routers = new ArrayList(); + } + + this.url = url; + String routerkey = url.getParameter(Constants.ROUTER_KEY); + if (routerkey != null && routerkey.length()>0 ){ + RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey); + routers.add(routerFactory.getRouter(url)); + } + if (routers != null) { + setRouters(routers); + } + } + + public List> list(Invocation invocation) throws RpcException { + List> invokers = doList(invocation); + for (Router router: routers){ + invokers = router.route(invokers, invocation); + } + return invokers; + } + + public URL getUrl() { + return url; + } + + public List getRouters(){ + return routers; + } + + protected abstract List> doList(Invocation invocation) throws RpcException ; + + protected void setRouters(List r){ + routers = r; + } + + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AvailableCluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AvailableCluster.java new file mode 100644 index 0000000000..0ef2630136 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AvailableCluster.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * AvailableCluster + * + * @author william.liangf + */ +@Extension(AvailableCluster.NAME) +public class AvailableCluster implements Cluster { + + public static final String NAME = "available"; + + public Invoker merge(Directory directory) throws RpcException { + + return new AbstractClusterInvoker(directory) { + public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + for (Invoker invoker : invokers) { + if (invoker.isAvailable()) { + return invoker.invoke(invocation); + } + } + throw new RpcException("No provider available in " + invokers); + } + }; + + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AvailableClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AvailableClusterInvoker.java new file mode 100644 index 0000000000..d86fce38f3 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/AvailableClusterInvoker.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.List; + +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * AvailableCluster + * + * @author william.liangf + */ +public class AvailableClusterInvoker extends AbstractClusterInvoker { + public AvailableClusterInvoker(Directory directory) { + super(directory); + } + + public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + for (Invoker invoker : invokers) { + if (invoker.isAvailable()) { + return invoker.invoke(invocation); + } + } + throw new RpcException("No provider available in " + invokers); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java new file mode 100644 index 0000000000..032ed6ff67 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java @@ -0,0 +1,77 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; + +/** + * ClusterUtils + * + * @author william.liangf + */ +public class ClusterUtils { + + public static URL mergeUrl(URL remoteUrl, Map localMap) { + Map map = new HashMap(); + Map remoteMap = remoteUrl.getParameters(); + if (remoteMap != null && remoteMap.size() > 0) { + map.putAll(remoteMap); + } + if (localMap != null && localMap.size() > 0) { + map.putAll(localMap); + } + if (remoteMap != null && remoteMap.size() > 0) { + // 版本号使用提供者的 + String dubbo = remoteMap.get(Constants.DUBBO_VERSION_KEY); + if (dubbo != null && dubbo.length() > 0) { + map.put(Constants.DUBBO_VERSION_KEY, dubbo); + } + String version = remoteMap.get(Constants.VERSION_KEY); + if (version != null && version.length() > 0) { + map.put(Constants.VERSION_KEY, version); + } + String group = remoteMap.get(Constants.GROUP_KEY); + if (group != null && group.length() > 0) { + map.put(Constants.GROUP_KEY, group); + } + String methods = remoteMap.get(Constants.METHODS_KEY); + if (methods != null && methods.length() > 0) { + map.put(Constants.METHODS_KEY, methods); + } + // 合并filter和listener + String remoteFilter = remoteMap.get(Constants.REFERENCE_FILTER_KEY); + String localFilter = localMap.get(Constants.REFERENCE_FILTER_KEY); + if (remoteFilter != null && remoteFilter.length() > 0 + && localFilter != null && localFilter.length() > 0) { + localMap.put(Constants.REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter); + } + String remoteListener = remoteMap.get(Constants.INVOKER_LISTENER_KEY); + String localListener = localMap.get(Constants.INVOKER_LISTENER_KEY); + if (remoteListener != null && remoteListener.length() > 0 + && localListener != null && localListener.length() > 0) { + localMap.put(Constants.INVOKER_LISTENER_KEY, remoteListener + "," + localListener); + } + } + return remoteUrl.addParameters(map); + } + + private ClusterUtils() {} + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackCluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackCluster.java new file mode 100644 index 0000000000..e16c06836e --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackCluster.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * 失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。 + * + * Failback + * + * @author william.liangf + */ +@Extension(FailbackCluster.NAME) +public class FailbackCluster implements Cluster { + public final static String NAME = "failback"; + + public Invoker merge(Directory directory) throws RpcException { + return new FailbackClusterInvoker(directory); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java new file mode 100644 index 0000000000..ae52ac74d4 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java @@ -0,0 +1,113 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * FailBackClusterInvoker.java + * + * @author tony.chenl + */ +public class FailbackClusterInvoker extends AbstractClusterInvoker { + + public FailbackClusterInvoker(Directory directory){ + super(directory); + } + + private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class); + + private static final long RETRY_FAILED_PERIOD = 5 * 1000; + + private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2, + new NamedThreadFactory( + "failback-cluster-timer", + true)); + + private volatile ScheduledFuture retryFuture; + + private final ConcurrentMap> failed = new ConcurrentHashMap>(); + + private void addFailed(Invocation invocation, AbstractClusterInvoker router) { + if (retryFuture == null) { + synchronized (this) { + if (retryFuture == null) { + retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + + public void run() { + // 收集统计信息 + try { + retryFailed(); + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at collect statistic", t); + } + } + }, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS); + } + } + } + failed.put(invocation, router); + } + + void retryFailed() { + if (failed.size() == 0) { + return; + } + for (Map.Entry> entry : new HashMap>( + failed).entrySet()) { + Invocation invocation = entry.getKey(); + Invoker invoker = entry.getValue(); + try { + invoker.invoke(invocation); + failed.remove(invocation); + } catch (Throwable e) { + logger.error("Failed retry to invoke " + invocation + ", waiting again.", e); + } + } + } + + protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + Invoker invoker = select(loadbalance, invocation, invokers, null); + try { + return invoker.invoke(invocation); + } catch (Throwable e) { + logger.error("Failback to invoke " + invocation + ", wait for retry in background. Ignored exception: " + + e.getMessage() + ", ", e); + addFailed(invocation, this); + return new RpcResult(); // ignore + } + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastCluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastCluster.java new file mode 100644 index 0000000000..3945f2be3a --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastCluster.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * 快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。
+ * Fail-fast + * + * @author william.liangf + */ +@Extension(FailfastCluster.NAME) +public class FailfastCluster implements Cluster { + public final static String NAME = "failfast"; + + public Invoker merge(Directory directory) throws RpcException { + return new FailfastClusterInvoker(directory); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java new file mode 100644 index 0000000000..2c77b96662 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * 快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。
+ * Fail-fast + * + * @author william.liangf + * @author chao.liuc + * + */ +public class FailfastClusterInvoker extends AbstractClusterInvoker{ + public FailfastClusterInvoker(Directory directory) { + super(directory); + } + + public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + + Invoker invoker = select(loadbalance, invocation, invokers, null); + try { + return invoker.invoke(invocation); + } catch (Throwable e) { + throw new RpcException("Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getAnnotation(Extension.class).value() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailoverCluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailoverCluster.java new file mode 100644 index 0000000000..d004412e1d --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailoverCluster.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。 Failover + * + * @author william.liangf + */ +@Extension(FailoverCluster.NAME) +public class FailoverCluster implements Cluster { + + public final static String NAME = "failover"; + + public Invoker merge(Directory directory) throws RpcException { + + return new FailoverClusterInvoker(directory); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvoker.java new file mode 100644 index 0000000000..48b4abe5ca --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvoker.java @@ -0,0 +1,86 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。 + * + * Failover + * @author william.liangf + * + */ +public class FailoverClusterInvoker extends AbstractClusterInvoker{ + public FailoverClusterInvoker(Directory directory) { + super(directory); + } + + public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + if (invokers == null || invokers.size() == 0) + throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started."); + + int len = getUrl().getMethodIntParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1; + if (len <= 0) + len = 1; + + // retry loop. + Throwable le = null; // last exception. + List> invoked = new ArrayList>(invokers.size()); // invoked invokers. + Set providers = new HashSet(len); + for (int i = 0; i < len; i++) { + //boolean pp = false; // is provider problem. + Invoker invoker = select(loadbalance, invocation, invokers, invoked); + invoked.add(invoker); + providers.add(invoker.getUrl()); + try { + return invoker.invoke(invocation); + } catch (RpcException e) { + if (e.isBiz()) throw e; + + le = e; + //pp = true; + } catch (Throwable e) // biz exception. + { + throw new RpcException(e.getMessage(), e); + } finally { + //if (pp) // if provider problem, fail over. + // inv.setWeight(0); + } + } + List urls = new ArrayList(invokers.size()); + for(Invoker invoker : invokers){ + if(invoker != null ) + urls.add(invoker.getUrl()); + } + throw new RpcException("Tried " + len + " times to invoke providers " + providers + " " + loadbalance.getClass().getAnnotation(Extension.class).value() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + (le != null ? le.getMessage() : ""), le); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeCluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeCluster.java new file mode 100644 index 0000000000..2bf974bb0f --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeCluster.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * 失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。 Fail-safe + * + * @author william.liangf + */ +@Extension(FailsafeCluster.NAME) +public class FailsafeCluster implements Cluster { + + public final static String NAME = "failsafe"; + + public Invoker merge(Directory directory) throws RpcException { + return new FailsafeClusterInvoker(directory); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java new file mode 100644 index 0000000000..aa982984b4 --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.List; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * 失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。 + * + * Fail-safe + * + * @author william.liangf + */ +public class FailsafeClusterInvoker extends AbstractClusterInvoker{ + private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class); + + public FailsafeClusterInvoker(Directory directory) { + super(directory); + } + + public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + Invoker invoker = select(loadbalance, invocation, invokers, null); + try { + return invoker.invoke(invocation); + } catch (Throwable e) { + logger.error("Failsafe ignore exception: " + e.getMessage(), e); + return new RpcResult(); // ignore + } + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingCluster.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingCluster.java new file mode 100644 index 0000000000..f57cda0f5f --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingCluster.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * 并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。 + * + * @author william.liangf + */ +@Extension(ForkingCluster.NAME) +public class ForkingCluster implements Cluster { + + public final static String NAME = "forking"; + + public Invoker merge(Directory directory) throws RpcException { + return new ForkingClusterInvoker(directory); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java new file mode 100644 index 0000000000..50aa4236cd --- /dev/null +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java @@ -0,0 +1,89 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * 并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。 + * + * @author william.liangf + */ +public class ForkingClusterInvoker extends AbstractClusterInvoker{ + + public ForkingClusterInvoker(Directory directory) { + super(directory); + } + + private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("forking-cluster-timer", true)); + + public Result doInvoke(final Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + final List> selected; + final int forks = getUrl().getIntParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS); + final int timeout = getUrl().getIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + if (forks <= 0 || forks >= invokers.size()) { + selected = invokers; + } else { + selected = new ArrayList>(); + for (int i = 0; i < forks; i++) { + //在invoker列表(排除selected)后,如果没有选够,则存在重复循环问题.见select实现. + Invoker invoker = select(loadbalance, invocation, invokers, selected); + if(!selected.contains(invoker)){//防止重复添加invoker + selected.add(invoker); + } + } + } + final AtomicInteger count = new AtomicInteger(); + final BlockingQueue ref = new LinkedBlockingQueue(); + for (final Invoker invoker : selected) { + executor.execute(new Runnable() { + public void run() { + try { + Result result = invoker.invoke(invocation); + ref.offer(result); + } catch(Throwable e) { + int value = count.incrementAndGet(); + if (value >= selected.size()) { + ref.offer(new RpcResult(e)); + } + } + } + }); + } + try { + return ref.poll(timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RpcException("Failed to forking invoke provider " + selected + ", cause: " + e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.Cluster b/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.Cluster new file mode 100644 index 0000000000..f952821cab --- /dev/null +++ b/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.Cluster @@ -0,0 +1,6 @@ +com.alibaba.dubbo.rpc.cluster.support.FailoverCluster +com.alibaba.dubbo.rpc.cluster.support.FailfastCluster +com.alibaba.dubbo.rpc.cluster.support.FailsafeCluster +com.alibaba.dubbo.rpc.cluster.support.FailbackCluster +com.alibaba.dubbo.rpc.cluster.support.ForkingCluster +com.alibaba.dubbo.rpc.cluster.support.AvailableCluster \ No newline at end of file diff --git a/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.LoadBalance b/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.LoadBalance new file mode 100644 index 0000000000..6bf44c0d97 --- /dev/null +++ b/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.LoadBalance @@ -0,0 +1,4 @@ +com.alibaba.dubbo.rpc.cluster.loadbalance.LoadBalanceAdptive +com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance +com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance +com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance \ No newline at end of file diff --git a/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.RouterFactory b/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.RouterFactory new file mode 100644 index 0000000000..a5021fb88b --- /dev/null +++ b/dubbo-cluster/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.cluster.RouterFactory @@ -0,0 +1,2 @@ +com.alibaba.dubbo.rpc.cluster.router.FileRouterFactory +com.alibaba.dubbo.rpc.cluster.router.ScriptRouterFactory \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/StickyTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/StickyTest.java new file mode 100644 index 0000000000..05ebe88d84 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/StickyTest.java @@ -0,0 +1,164 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster; + + +import java.util.ArrayList; +import java.util.List; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; +import com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker; +@SuppressWarnings("unchecked") +public class StickyTest { + + List> invokers = new ArrayList>(); + + + Invoker invoker1 = EasyMock.createMock(Invoker.class); + Invoker invoker2 = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic ; + Result result = new RpcResult(); + StickyClusterInvoker clusterinvoker = null; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(StickyTest.class).anyTimes(); + EasyMock.replay(dic); + invokers.add(invoker1); + invokers.add(invoker2); + + clusterinvoker = new StickyClusterInvoker(dic); + } + URL url = URL.valueOf("test://test:11/test?" + +"&loadbalance=roundrobin" +// +"&"+RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY+"=true" + +"&"+RpcConstants.CLUSTER_STICKY_KEY+"=true" + ); + + int runs = 1; + @Test + public void testStickyNoCheck() { + int count = testSticky(null,false); + System.out.println(count); + Assert.assertTrue(count>0 && count <=runs); + } + + @Test + public void testStickyForceCheck() { + int count = testSticky(null,true); + Assert.assertTrue(count == 0 || count == runs); + } + @Test + public void testMethodStickyNoCheck() { + int count = testSticky("method1",false); + System.out.println(count); + Assert.assertTrue(count>0 && count <=runs); + } + + @Test + public void testMethodStickyForceCheck() { + int count = testSticky("method1",true); + Assert.assertTrue(count == 0 || count == runs); + } + + @Test + public void testMethodsSticky() { + for(int i = 0 ;i<100 ; i++){//多次调用看两个方法是否都选在同一个invoker + int count1 = testSticky("method1",true); + int count2 = testSticky("method2",true); + Assert.assertTrue(count1 == count2); + } + } + + public int testSticky(String methodName, boolean check) { + if (methodName == null){ + url = url.addParameter(RpcConstants.CLUSTER_STICKY_KEY, String.valueOf(check)); + }else { + url = url.addParameter(methodName+"."+RpcConstants.CLUSTER_STICKY_KEY, String.valueOf(check)); + } + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(StickyTest.class).anyTimes(); + EasyMock.replay(invoker1); + + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(StickyTest.class).anyTimes(); + EasyMock.replay(invoker2); + + EasyMock.reset(invocation); + EasyMock.expect(invocation.getMethodName()).andReturn(methodName).anyTimes(); + EasyMock.replay(invocation); + + int count = 0; + for (int i = 0; i < runs; i++) { + Assert.assertEquals(null, clusterinvoker.invoke(invocation)); + if(invoker1 == clusterinvoker.getSelectedInvoker()){ + count ++; + } + } + return count; + } + + + static class StickyClusterInvoker extends AbstractClusterInvoker{ + private Invoker selectedInvoker ; + public StickyClusterInvoker(Directory directory) { + super(directory); + } + public StickyClusterInvoker(Directory directory,URL url) { + super(directory, url); + } + @Override + protected Result doInvoke(Invocation invocation, List> invokers, + LoadBalance loadbalance) throws RpcException { + Invoker invoker = select(loadbalance, invocation, invokers, null); + selectedInvoker = invoker ; + return null; + } + public Invoker getSelectedInvoker() { + return selectedInvoker; + } + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoService.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoService.java new file mode 100644 index 0000000000..373e7d1de0 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoService.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.filter; + +/** + * TestService + */ + +public interface DemoService +{ + String sayHello(String name); + + int plus(int a,int b); +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceLocal.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceLocal.java new file mode 100644 index 0000000000..8f2902849c --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceLocal.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.filter; + +/** + * TestService + */ + +public class DemoServiceLocal implements DemoService { + + public DemoServiceLocal(DemoService demoService){ + } + + public String sayHello(String name) { + return name; + } + + public int plus(int a, int b) { + return a + b; + } + + public void ondisconnect(){ + + } + + public void onconnect(){ + + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceMock.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceMock.java new file mode 100644 index 0000000000..b1b7b4ab88 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceMock.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.filter; + +/** + * MockService.java + * @author tony.chenl + */ +public class DemoServiceMock implements DemoService{ + public String sayHello(String name) { + return name; + } + + public int plus(int a, int b) { + return a+b; + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceStub.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceStub.java new file mode 100644 index 0000000000..c9bcb6cfb5 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/DemoServiceStub.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.filter; + +/** + * TestService + */ + +public class DemoServiceStub implements DemoService { + + public DemoServiceStub(DemoService demoService){ + } + + public String sayHello(String name) { + return name; + } + + public int plus(int a, int b) { + return a + b; + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/MockService.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/MockService.java new file mode 100644 index 0000000000..a8a2d3a0e6 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/filter/MockService.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.filter; + +/** + * MockService.java + * @author tony.chenl + */ +public class MockService implements DemoService{ + public String sayHello(String name) { + return name; + } + + public int plus(int a, int b) { + return a+b; + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java new file mode 100644 index 0000000000..7ca6ec1e9d --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.loadbalance; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.jboss.netty.util.internal.ConcurrentHashMap; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * RoundRobinLoadBalanceTest + * @author liuchao + * + */ +@SuppressWarnings({ "unchecked", "rawtypes" }) +public class LoadBalanceTest { + Invocation invocation ; + List> invokers = new ArrayList>(); + Invoker invoker1 ; + Invoker invoker2 ; + Invoker invoker3 ; + Invoker invoker4 ; + Invoker invoker5 ; + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + + + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + + invoker1 = EasyMock.createMock(Invoker.class); + invoker2 = EasyMock.createMock(Invoker.class); + invoker3 = EasyMock.createMock(Invoker.class); + invoker4 = EasyMock.createMock(Invoker.class); + invoker5 = EasyMock.createMock(Invoker.class); + + URL url = URL.valueOf("test://127.0.0.1/DemoService"); + + EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(LoadBalanceTest.class).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(LoadBalanceTest.class).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + + EasyMock.expect(invoker3.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker3.getInterface()).andReturn(LoadBalanceTest.class).anyTimes(); + EasyMock.expect(invoker3.getUrl()).andReturn(url).anyTimes(); + + EasyMock.expect(invoker4.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker4.getInterface()).andReturn(LoadBalanceTest.class).anyTimes(); + EasyMock.expect(invoker4.getUrl()).andReturn(url).anyTimes(); + + EasyMock.expect(invoker5.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker5.getInterface()).andReturn(LoadBalanceTest.class).anyTimes(); + EasyMock.expect(invoker5.getUrl()).andReturn(url).anyTimes(); + + EasyMock.replay(invocation,invoker1,invoker2,invoker3,invoker4,invoker5); + + invokers.add(invoker1); + invokers.add(invoker2); + invokers.add(invoker3); + invokers.add(invoker4); + invokers.add(invoker5); + } + + @Test + public void testRoundRobinLoadBalance_select() { + int runs = 10000; + Map counter = getInvokeCounter(runs,RoundRobinLoadBalance.NAME); + for (Invoker minvoker :counter.keySet() ){ + Long count = counter.get(minvoker).get(); + Assert.assertTrue("abs diff shoud < 1", Math.abs(count-runs/(0f+invokers.size())) <1f); + } + } + @Test + public void testRandomLoadBalance_select() { + int runs = 1000; + Map counter = getInvokeCounter(runs,RandomLoadBalance.NAME); + for (Invoker minvoker :counter.keySet() ){ + Long count = counter.get(minvoker).get(); +// System.out.println(count); + Assert.assertTrue("abs diff shoud < avg", Math.abs(count-runs/(0f+invokers.size())) counter = getInvokeCounter(runs,LeastActiveLoadBalance.NAME); + for (Invoker minvoker :counter.keySet() ){ + Long count = counter.get(minvoker).get(); +// System.out.println(count); + Assert.assertTrue("abs diff shoud < avg", Math.abs(count-runs/(0f+invokers.size())) getInvokeCounter(int runs,String loadbalanceName) { + Map counter = new ConcurrentHashMap(); + LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName); + for(Invoker invoker :invokers){ + counter.put(invoker, new AtomicLong(0)); + } + for(int i=0;i implements Invoker { + private boolean available = false; + private URL url ; + + public MockInvoker() { + } + public MockInvoker(URL url) { + super(); + this.url = url; + } + public MockInvoker(boolean available) { + this.available = available; + } + + public Class getInterface() { + return null; + } + + public URL getUrl() { + return url; + } + + public boolean isAvailable() { + return available; + } + + public Result invoke(Invocation invocation) throws RpcException { + return null; + } + + public void destroy() { + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouterEngineTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouterEngineTest.java new file mode 100644 index 0000000000..83adb88c53 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/ScriptRouterEngineTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.router; + + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.cluster.Router; + +public class ScriptRouterEngineTest { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + private URL SCRIPT_URL = URL.valueOf("script://javascript?type=javascript"); + + private URL getRouteUrl(String rule) { + return SCRIPT_URL.addParameterAndEncoded(RpcConstants.RULE_KEY, rule); + } + + @Test + public void testRoute_ReturnAll(){ + Router router = new ScriptRouterFactory().getRouter(getRouteUrl("function route(op1,op2){return op1} route(invokers)")); + List> invokers = new ArrayList>(); + invokers.add(new MockInvoker()); + invokers.add(new MockInvoker()); + invokers.add(new MockInvoker()); + List> fileredInvokers = router.route(invokers, new RpcInvocation()); + Assert.assertEquals(invokers, fileredInvokers); + } + + @Test + public void testRoute_PickInvokers(){ + String rule = "var result = new java.util.ArrayList(invokers.size());" + + "for (i=0;i> invokers = new ArrayList>(); + Invoker invoker1 = new MockInvoker(false) ; + Invoker invoker2 = new MockInvoker(true) ; + Invoker invoker3 = new MockInvoker(true) ; + invokers.add(invoker1); + invokers.add(invoker2); + invokers.add(invoker3); + List> fileredInvokers = router.route(invokers, new RpcInvocation()); + Assert.assertEquals(2, fileredInvokers.size()); + Assert.assertEquals(invoker2, fileredInvokers.get(0)); + Assert.assertEquals(invoker3, fileredInvokers.get(1)); + } + //TODO 异常场景测试。 +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java new file mode 100644 index 0000000000..4f333d73eb --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java @@ -0,0 +1,187 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.router.file; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; +import com.alibaba.dubbo.rpc.cluster.RouterFactory; +import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory; +import com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker; + +/** + * @author chao.liuc + */ +@SuppressWarnings("unchecked") +public class FileRouterEngineTest { + List> invokers = new ArrayList>(); + + Invoker invoker1 = EasyMock.createMock(Invoker.class); + Invoker invoker2 = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic; + Result result = new RpcResult(); + private RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + invokers.add(invoker1); + invokers.add(invoker2); + } + + @Test + public void testRouteNotAvailable() { + URL url = initUrl("notAvailablerule.javascript"); + initInvocation("method1"); + initDic(url); + initInvokers(url, true, false); + + MockClusterInvoker sinvoker = new MockClusterInvoker( + dic, url); + for (int i = 0; i < 100; i++) { + sinvoker.invoke(invocation); + Invoker invoker = sinvoker.getSelectedInvoker(); + Assert.assertEquals(invoker2, invoker); + } + } + + @Test + public void testRouteAvailable() { + URL url = initUrl("availablerule.javascript"); + initInvocation("method1"); + initDic(url); + initInvokers(url); + + MockClusterInvoker sinvoker = new MockClusterInvoker( + dic, url); + for (int i = 0; i < 100; i++) { + sinvoker.invoke(invocation); + Invoker invoker = sinvoker.getSelectedInvoker(); + Assert.assertEquals(invoker1, invoker); + } + } + + @Test + public void testRouteByMethodName() { + URL url = initUrl("methodrule.javascript"); + { + initInvocation("method1"); + initDic(url); + initInvokers(url, true, true); + + MockClusterInvoker sinvoker = new MockClusterInvoker( + dic, url); + for (int i = 0; i < 100; i++) { + sinvoker.invoke(invocation); + Invoker invoker = sinvoker.getSelectedInvoker(); + Assert.assertEquals(invoker1, invoker); + } + } + { + initInvocation("method2"); + initDic(url); + initInvokers(url, true, true); + MockClusterInvoker sinvoker = new MockClusterInvoker( + dic, url); + for (int i = 0; i < 100; i++) { + sinvoker.invoke(invocation); + Invoker invoker = sinvoker.getSelectedInvoker(); + Assert.assertEquals(invoker2, invoker); + } + } + } + + private URL initUrl(String filename) { + filename = FileRouterEngineTest.class.getResource(filename).toString(); + URL url = URL.valueOf(filename.replaceAll("file:/", "file:///")); + return url; + } + + private void initInvocation(String methodName) { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn(methodName).anyTimes(); + EasyMock.replay(invocation); + } + + private void initInvokers(URL url) { + initInvokers(url, true, false); + } + + private void initInvokers(URL url, boolean invoker1Status, boolean invoker2Status) { + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(invoker1Status).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(FileRouterEngineTest.class).anyTimes(); + EasyMock.replay(invoker1); + + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(invoker2Status).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(FileRouterEngineTest.class).anyTimes(); + EasyMock.replay(invoker2); + } + + private void initDic(URL url) { + dic = new StaticDirectory(url, invokers, Arrays.asList(routerFactory.getRouter(url))); + } + + static class MockClusterInvoker extends AbstractClusterInvoker { + private Invoker selectedInvoker; + + public MockClusterInvoker(Directory directory) { + super(directory); + } + + public MockClusterInvoker(Directory directory, URL url) { + super(directory, url); + } + + @Override + protected Result doInvoke(Invocation invocation, List> invokers, + LoadBalance loadbalance) throws RpcException { + Invoker invoker = select(loadbalance, invocation, invokers, null); + selectedInvoker = invoker; + return null; + } + + public Invoker getSelectedInvoker() { + return selectedInvoker; + } + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/availablerule.javascript b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/availablerule.javascript new file mode 100644 index 0000000000..c76de32ee4 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/availablerule.javascript @@ -0,0 +1,11 @@ +function route(invokers,invocation,context){ + var result = new java.util.ArrayList(invokers.size()); + + for (i=0;i1 && invocation.getMethodName() .equals("method1")) { + result.add(invokers.get(0)) ; + } else { + result.add(invokers.get(1)) ; + } + return result; +}; +route(invokers,invocation,context); \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/notAvailablerule.javascript b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/notAvailablerule.javascript new file mode 100644 index 0000000000..1fcdcaeb0d --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/router/file/notAvailablerule.javascript @@ -0,0 +1,11 @@ +function route(invokers,invocation,context){ + var result = new java.util.ArrayList(invokers.size()); + + for (i=0;i> invokers = new ArrayList>(); + List> selectedInvokers = new ArrayList>(); + AbstractClusterInvoker cluster; + AbstractClusterInvoker cluster_nocheck; + Directory dic ; + Invocation invocation; + URL url = URL.valueOf("registry://localhost:9090"); + + Invoker invoker1 ; + Invoker invoker2 ; + Invoker invoker3 ; + Invoker invoker4 ; + Invoker invoker5 ; + + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + @SuppressWarnings({ "unchecked" }) + @Before + public void setUp() throws Exception { + dic = EasyMock.createMock(Directory.class); + + invoker1 = EasyMock.createMock(Invoker.class); + invoker2 = EasyMock.createMock(Invoker.class); + invoker3 = EasyMock.createMock(Invoker.class); + invoker4 = EasyMock.createMock(Invoker.class); + invoker5 = EasyMock.createMock(Invoker.class); + + URL turl = URL.valueOf("test://test:11/test"); + + EasyMock.expect(invoker1.isAvailable()).andReturn(false).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(turl.addParameter("name", "invoker1")).anyTimes(); + + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(turl.addParameter("name", "invoker2")).anyTimes(); + + EasyMock.expect(invoker3.isAvailable()).andReturn(false).anyTimes(); + EasyMock.expect(invoker3.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes(); + EasyMock.expect(invoker3.getUrl()).andReturn(turl.addParameter("name", "invoker3")).anyTimes(); + + EasyMock.expect(invoker4.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker4.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes(); + EasyMock.expect(invoker4.getUrl()).andReturn(turl.addParameter("name", "invoker4")).anyTimes(); + + EasyMock.expect(invoker5.isAvailable()).andReturn(false).anyTimes(); + EasyMock.expect(invoker5.getInterface()).andReturn(AbstractClusterInvokerTest.class).anyTimes(); + EasyMock.expect(invoker5.getUrl()).andReturn(turl.addParameter("name", "invoker5")).anyTimes(); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invoker1,invoker2,invoker3,invoker4,invoker5,invocation); + + cluster = new AbstractClusterInvoker(dic) { + @Override + protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance) + throws RpcException { + return null; + } + }; + + cluster_nocheck = new AbstractClusterInvoker(dic,url.addParameterIfAbsent(RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY, Boolean.FALSE.toString())) { + @Override + protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance) + throws RpcException { + return null; + } + }; + } + + @Test + public void testSelect_Invokersize0() throws Exception { + { + Invoker invoker = cluster.select(null,null,null,null); + Assert.assertEquals(null, invoker); + } + { + invokers.clear(); + selectedInvokers.clear(); + Invoker invoker = cluster.select(null,null,invokers,null); + Assert.assertEquals(null, invoker); + } + } + + @Test + public void testSelect_Invokersize1() throws Exception { + invokers.clear(); + invokers.add(invoker1); + Invoker invoker = cluster.select(null,null,invokers,null); + Assert.assertEquals(invoker1, invoker); + } + + @Test + public void testSelect_Invokersize2AndselectNotNull() throws Exception { + invokers.clear(); + invokers.add(invoker1); + invokers.add(invoker2); + { + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + Invoker invoker = cluster.select(null,null,invokers,selectedInvokers); + Assert.assertEquals(invoker2, invoker); + } + { + selectedInvokers.clear(); + selectedInvokers.add(invoker2); + Invoker invoker = cluster.select(null,null,invokers,selectedInvokers); + Assert.assertEquals(invoker1, invoker); + } + } + + @Test + public void testSelect_multiInvokers() throws Exception { + testSelect_multiInvokers( RoundRobinLoadBalance.NAME); + testSelect_multiInvokers( LeastActiveLoadBalance.NAME); + testSelect_multiInvokers( RandomLoadBalance.NAME); + } + + @Test + public void testCloseAvailablecheck(){ + LoadBalance lb = EasyMock.createMock(LoadBalance.class); + EasyMock.expect(lb.select(invokers, invocation)).andReturn(invoker1); + EasyMock.replay(lb); + initlistsize5(); + + Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers); + Assert.assertEquals(false,sinvoker.isAvailable()); + Assert.assertEquals(invoker1,sinvoker); + + } + + @Test + public void testDonotSelectAgainAndNoCheckAvailable(){ + + LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME); + initlistsize5(); + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker4); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers); + Assert.assertSame(invoker1, sinvoker); + } + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker4); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers); + Assert.assertSame(invoker2, sinvoker); + } + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker4); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers ); + Assert.assertSame(invoker3, sinvoker); + } + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker4); + Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers ); + Assert.assertSame(invoker5, sinvoker); + } + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker4); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers); + Assert.assertTrue(invokers.contains(sinvoker)); + } + + } + + @Test + public void testSelectAgainAndCheckAvailable(){ + + LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME); + initlistsize5(); + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers); + Assert.assertTrue(sinvoker == invoker4 ); + } + { + //边界测试. + selectedInvokers.clear(); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker4); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers); + Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4); + } + { + //边界测试. + for(int i=0;i<100;i++){ + selectedInvokers.clear(); + Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers); + Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4); + } + } + { + //边界测试. + for(int i=0;i<100;i++){ + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers); + Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4); + } + } + { + //边界测试. + for(int i=0;i<100;i++){ + selectedInvokers.clear(); + selectedInvokers.add(invoker1); + selectedInvokers.add(invoker3); + selectedInvokers.add(invoker2); + selectedInvokers.add(invoker4); + selectedInvokers.add(invoker5); + Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers); + Assert.assertTrue(sinvoker == invoker2 || sinvoker == invoker4); + } + } + } + + + public void testSelect_multiInvokers(String lbname) throws Exception { + + int min=1000,max=5000; + Double d = (Math.random()*(max-min+1)+min); + int runs = d.intValue(); + Assert.assertTrue(runs>min); + LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(lbname); + initlistsize5(); + for(int i=0;i counter = new ConcurrentHashMap(); + for(Invoker invoker :invokers){ + counter.put(invoker, new AtomicLong(0)); + } + int runs = 1000; + for(int i=0;i avg", count>runs/invokers.size()); + } + + Assert.assertEquals(runs, counter.get(invoker2).get()+counter.get(invoker4).get());; + + } + + private void initlistsize5(){ + invokers.clear(); + selectedInvokers.clear();//需要清除,之前的测试中会主动将正确的invoker2放入其中. + invokers.add(invoker1); + invokers.add(invoker2); + invokers.add(invoker3); + invokers.add(invoker4); + invokers.add(invoker5); + } + @Test + public void testInvoke() { +// fail("Not yet implemented"); + } + + @Test + public void testDoInvoke() { +// fail("Not yet implemented"); + } + + +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java new file mode 100644 index 0000000000..14bcac2fb8 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.filter.DemoService; + +/** + * FailfastClusterInvokerTest + * @author tony.chenl + * + */ +@SuppressWarnings("unchecked") +public class FailSafeClusterInvokerTest { + List> invokers = new ArrayList>(); + URL url = URL.valueOf("test://test:11/test"); + Invoker invoker = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic ; + Result result = new RpcResult(); + /** + * @throws java.lang.Exception + */ + + @Before + public void setUp() throws Exception { + + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(DemoService.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invocation); + + invokers.add(invoker); + } + + @After + public void tearDown(){ + EasyMock.verify(invoker,dic,invocation); + + } + private void resetInvokerToException(){ + EasyMock.reset(invoker); + EasyMock.expect(invoker.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + EasyMock.replay(invoker); + } + private void resetInvokerToNoException(){ + EasyMock.reset(invoker); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + EasyMock.replay(invoker); + } + + //TODO assert error log + @Test + public void testInvokeExceptoin() { + resetInvokerToException(); + FailsafeClusterInvoker invoker = new FailsafeClusterInvoker(dic); + invoker.invoke(invocation); + Assert.assertNull(RpcContext.getContext().getInvoker()); + } + + @Test() + public void testInvokeNoExceptoin() { + + resetInvokerToNoException(); + + FailsafeClusterInvoker invoker = new FailsafeClusterInvoker(dic); + Result ret = invoker.invoke(invocation); + Assert.assertSame(result, ret); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java new file mode 100644 index 0000000000..ac227e49d8 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * FailbackClusterInvokerTest + * + * @author tony.chenl + */ +@SuppressWarnings("unchecked") +public class FailbackClusterInvokerTest { + + List> invokers = new ArrayList>(); + URL url = URL.valueOf("test://test:11/test"); + Invoker invoker = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic; + Result result = new RpcResult(); + + /** + * @throws java.lang.Exception + */ + + @Before + public void setUp() throws Exception { + + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic, invocation); + + invokers.add(invoker); + } + + @After + public void tearDown() { + EasyMock.verify(invoker, dic, invocation); + + } + + private void resetInvokerToException() { + EasyMock.reset(invoker); + EasyMock.expect(invoker.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker); + } + + private void resetInvokerToNoException() { + EasyMock.reset(invoker); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker); + } + + @Test + public void testInvokeExceptoin() { + resetInvokerToException(); + FailbackClusterInvoker invoker = new FailbackClusterInvoker( + dic); + invoker.invoke(invocation); + Assert.assertNull(RpcContext.getContext().getInvoker()); + } + + @Test() + public void testInvokeNoExceptoin() { + + resetInvokerToNoException(); + + FailbackClusterInvoker invoker = new FailbackClusterInvoker( + dic); + Result ret = invoker.invoke(invocation); + Assert.assertSame(result, ret); + } + + @Test() + public void testRetryFailed() { + + resetInvokerToException(); + + FailbackClusterInvoker invoker = new FailbackClusterInvoker( + dic); + invoker.invoke(invocation); + Assert.assertNull(RpcContext.getContext().getInvoker()); + invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so + // it can be invoke successfully + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java new file mode 100644 index 0000000000..7e2f8ccc7b --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java @@ -0,0 +1,108 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * FailfastClusterInvokerTest + * @author liuchao + * + */ +@SuppressWarnings("unchecked") +public class FailfastClusterInvokerTest { + List> invokers = new ArrayList>(); + URL url = URL.valueOf("test://test:11/test"); + Invoker invoker1 = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic ; + Result result = new RpcResult(); + /** + * @throws java.lang.Exception + */ + + @Before + public void setUp() throws Exception { + + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invocation); + + invokers.add(invoker1); + } + + @After + public void tearDown(){ + EasyMock.verify(invoker1,dic,invocation); + + } + private void resetInvoker1ToException(){ + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + } + private void resetInvoker1ToNoException(){ + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + } + + @Test(expected = RpcException.class) + public void testInvokeExceptoin() { + resetInvoker1ToException(); + FailfastClusterInvoker invoker = new FailfastClusterInvoker(dic); + invoker.invoke(invocation); + Assert.assertSame(invoker1, RpcContext.getContext().getInvoker()); + } + + @Test() + public void testInvokeNoExceptoin() { + + resetInvoker1ToNoException(); + + FailfastClusterInvoker invoker = new FailfastClusterInvoker(dic); + Result ret = invoker.invoke(invocation); + Assert.assertSame(result, ret); + } + +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java new file mode 100644 index 0000000000..67b3895fb8 --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java @@ -0,0 +1,142 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * FailoverClusterInvokerTest + * @author liuchao + * + */ +@SuppressWarnings("unchecked") +public class FailoverClusterInvokerTest { + List> invokers = new ArrayList>(); + int retries = 5; + URL url = URL.valueOf("test://test:11/test?retries="+retries); + Invoker invoker1 = EasyMock.createMock(Invoker.class); + Invoker invoker2 = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic ; + Result result = new RpcResult(); + /** + * @throws java.lang.Exception + */ + + @Before + public void setUp() throws Exception { + + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invocation); + + invokers.add(invoker1); + invokers.add(invoker2); + } + + + @Test(expected = RpcException.class) + public void testInvokeWithBizException() { + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker2); + + FailoverClusterInvoker invoker = new FailoverClusterInvoker(dic); + invoker.invoke(invocation); + } + + @Test() + public void testInvokeWithRPCException() { + + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RpcException()).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker2); + + FailoverClusterInvoker invoker = new FailoverClusterInvoker(dic); + for(int i=0;i<100;i++){ + Result ret = invoker.invoke(invocation); + Assert.assertSame(result, ret); + } + } + + @Test() + public void testInvoke_retryTimes() { + + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RpcException()).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(false).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RpcException()).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(false).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker2); + + FailoverClusterInvoker invoker = new FailoverClusterInvoker(dic); + try{ + Result ret = invoker.invoke(invocation); + Assert.assertSame(result, ret); + }catch (RpcException e) { + System.out.println(e.getMessage()); + Assert.assertTrue(e.getMessage().indexOf((retries+1)+" times")>0); + } + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java new file mode 100644 index 0000000000..79b826292b --- /dev/null +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.cluster.support; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; + +/** + * ForkingClusterInvokerTest + * + * @author tony.chenl + */ +@SuppressWarnings("unchecked") +public class ForkingClusterInvokerTest { + + List> invokers = new ArrayList>(); + URL url = URL.valueOf("test://test:11/test?forks=2"); + Invoker invoker1 = EasyMock.createMock(Invoker.class); + Invoker invoker2 = EasyMock.createMock(Invoker.class); + Invoker invoker3 = EasyMock.createMock(Invoker.class); + Invocation invocation; + Directory dic; + Result result = new RpcResult(); + + /** + * @throws java.lang.Exception + */ + + @Before + public void setUp() throws Exception { + + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic, invocation); + + invokers.add(invoker1); + invokers.add(invoker2); + invokers.add(invoker3); + + } + + @After + public void tearDown() { + EasyMock.verify(invoker1, dic, invocation); + + } + + private void resetInvokerToException() { + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker2); + EasyMock.reset(invoker3); + EasyMock.expect(invoker3.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); + EasyMock.expect(invoker3.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker3.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker3.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker3); + } + + private void resetInvokerToNoException() { + EasyMock.reset(invoker1); + EasyMock.expect(invoker1.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker1.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker1); + EasyMock.reset(invoker2); + EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker2.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker2); + EasyMock.reset(invoker3); + EasyMock.expect(invoker3.invoke(invocation)).andReturn(result).anyTimes(); + EasyMock.expect(invoker3.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(invoker3.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker3.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + EasyMock.replay(invoker3); + } + + @Test + public void testInvokeExceptoin() { + resetInvokerToException(); + ForkingClusterInvoker invoker = new ForkingClusterInvoker( + dic); + Assert.assertNull(invoker.invoke(invocation).getResult()); + Assert.assertNotNull(invoker.invoke(invocation).getException()); + } + + @Test() + public void testInvokeNoExceptoin() { + + resetInvokerToNoException(); + + ForkingClusterInvoker invoker = new ForkingClusterInvoker( + dic); + Result ret = invoker.invoke(invocation); + Assert.assertSame(result, ret); + } +} \ No newline at end of file diff --git a/dubbo-cluster/src/test/resources/log4j.xml b/dubbo-cluster/src/test/resources/log4j.xml new file mode 100644 index 0000000000..ae988c35f1 --- /dev/null +++ b/dubbo-cluster/src/test/resources/log4j.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml new file mode 100644 index 0000000000..5b24aa3a8c --- /dev/null +++ b/dubbo-common/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-common + jar + Dubbo Common Module + The common module of dubbo project + + + log4j + log4j + + + org.javassist + javassist + + + com.alibaba + hessian.lite + + + com.alibaba + fastjson + provided + + + \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Adaptive.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Adaptive.java new file mode 100644 index 0000000000..d297b1c001 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Adaptive.java @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 在{@link ExtensionLoader}生成Extension的Adaptive Instance时,为{@link ExtensionLoader}提供信息。 + * + * @author ding.lid + * + * @see ExtensionLoader + * @see URL + * @see Extension + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface Adaptive { + + /** + * 从{@link URL}的Key名,对应的Value作为要Adapt成的Extension名。 + *

+ * 如果{@link URL}这些Key都没有Value,使用 用 缺省的扩展(在接口的{@link Extension}中设定的值)。
+ * 比如,String[] {"key1", "key2"},表示 + *

    + *
  1. 先在URL上找key1的Value作为要Adapt成的Extension名; + *
  2. key1没有Value,则使用key2的Value作为要Adapt成的Extension名。 + *
  3. key2没有Value,使用缺省的扩展。 + *
  4. 如果没有设定缺省扩展,则方法调用会抛出{@link IllegalStateException}。 + *
+ *

+ * 如果不设置则缺省使用Extension接口类名的点分隔小写字串。
+ * 即对于Extension接口{@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}的缺省值为String[] {"yyy.invoker.wrapper"} + * + * @see Extension#value() + */ + String[] value() default {}; + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java new file mode 100644 index 0000000000..353302b4ce --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java @@ -0,0 +1,278 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Constants + * + * @author william.liangf + */ +public class Constants { + + public static final List DEFAULT_TELNET_COMMANDS = Collections.unmodifiableList(Arrays.asList(new String[] { + "ls", "ps", "cd", "pwd", "invoke", "count", "trace", "status", "help", "clear", "exit","log" })); + + public static final List DEFAULT_CHECK_STATUSES = Collections.unmodifiableList(Arrays.asList(new String[] { + "server", "registry", "threadpool", "datasource", "spring", "memory", "load" })); + + public static final String SENT_KEY = "sent"; + + public static final String REGISTRY_PROTOCOL = "registry"; + + public static final String $INVOKE = "$invoke"; + + public static final String $ECHO = "$echo"; + + public static final int DEFAULT_IO_THREADS = Runtime.getRuntime().availableProcessors() + 1; + + public static final String DEFAULT_PROXY = "javassist"; + + public static final int DEFAULT_PAYLOAD = 8 * 1024 * 1024; // 8M + + public static final String DEFAULT_CLUSTER = "failover"; + + public static final String DEFAULT_DIRECTORY = "dubbo"; + + public static final String DEFAULT_LOADBALANCE = "random"; + + public static final String DEFAULT_PROTOCOL = "dubbo"; + + public static final String DEFAULT_EXCHANGER = "header"; + + public static final String DEFAULT_TRANSPORTER = "netty"; + + public static final String DEFAULT_REMOTING_SERVER = "netty"; + + public static final String DEFAULT_REMOTING_CLIENT = "netty"; + + public static final String DEFAULT_REMOTING_CODEC = "dubbo"; + + public static final String DEFAULT_REMOTING_SERIALIZATION = "hessian2"; + + public static final String DEFAULT_HTTP_SERVER = "servlet"; + + public static final String DEFAULT_HTTP_CLIENT = "jdk"; + + public static final String DEFAULT_HTTP_SERIALIZATION = "json"; + + public static final String DEFAULT_CHARSET = "UTF-8"; + + public static final int DEFAULT_WEIGHT = 5; + + public static final int DEFAULT_FORKS = 2; + + public static final String DEFAULT_THREAD_NAME = "Dubbo"; + + public static final int DEFAULT_THREADS = 100; + + public static final int DEFAULT_QUEUES = 0; + + public static final int DEFAULT_THREAD_ALIVE = 60 * 1000; + + public static final int DEFAULT_CONNECTIONS = 0; + + public static final int DEFAULT_ACCEPTS = 0; + + public static final int DEFAULT_IDLE_TIMEOUT = 600 * 1000; + + public static final int DEFAULT_HEARTBEAT = 0; + + public static final int DEFAULT_TIMEOUT = 5000; + + public static final int DEFAULT_RETRIES = 2; + + // default buffer size is 8k. + public static final int DEFAULT_BUFFER_SIZE = 8 * 1024; + + public static final int MAX_BUFFER_SIZE = 16 * 1024; + + public static final int MIN_BUFFER_SIZE = 1 * 1024; + + public static final String REMOVE_VALUE_PREFIX = "-"; + + public static final String HIDE_KEY_PREFIX = "."; + + public static final String DEFAULT_KEY_PREFIX = "default."; + + public static final String DEFAULT_KEY = "default"; + + public static final String LOADBALANCE_KEY = "loadbalance"; + + public static final String ROUTER_KEY = "router"; + + public static final String CLUSTER_KEY = "cluster"; + + public static final String REGISTRY_KEY = "registry"; + + public static final String MONITOR_KEY = "monitor"; + + public static final String DEFAULT_REGISTRY = "dubbo"; + + public static final String BACKUP_KEY = "backup"; + + public static final String DIRECTORY_KEY = "directory"; + + public static final String DEPRECATED_KEY = "deprecated"; + + public static final String ANYHOST_KEY = "anyhost"; + + public static final String APPLICATION_KEY = "application"; + + public static final String LOCAL_KEY = "local"; + + public static final String STUB_KEY = "stub"; + + public static final String MOCK_KEY = "mock"; + + public static final String PROXY_KEY = "proxy"; + + public static final String WEIGHT_KEY = "weight"; + + public static final String FORKS_KEY = "forks"; + + public static final String DEFAULT_THREADPOOL = "fixed"; + + public static final String DEFAULT_CLIENT_THREADPOOL = "cached"; + + public static final String THREADPOOL_KEY = "threadpool"; + + public static final String THREAD_NAME_KEY = "threadname"; + + public static final String IO_THREADS_KEY = "iothreads"; + + public static final String THREADS_KEY = "threads"; + + public static final String QUEUES_KEY = "queues"; + + public static final String THREAD_ALIVE_KEY = "threadalive"; + + public static final String EXECUTES_KEY = "executes"; + + public static final String BUFFER_KEY = "buffer"; + + public static final String PAYLOAD_KEY = "payload"; + + public static final String REFERENCE_FILTER_KEY = "reference.filter"; + + public static final String INVOKER_LISTENER_KEY = "invoker.listener"; + + public static final String SERVICE_FILTER_KEY = "service.filter"; + + public static final String EXPORTER_LISTENER_KEY = "exporter.listener"; + + public static final String ACCESS_LOG_KEY = "accesslog"; + + public static final String ACTIVES_KEY = "actives"; + + public static final String CONNECTIONS_KEY = "connections"; + + public static final String ACCEPTS_KEY = "accepts"; + + public static final String IDLE_TIMEOUT_KEY = "idle.timeout"; + + public static final String HEARTBEAT_KEY = "heartbeat"; + + public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeat.timeout"; + + public static final String CONNECT_TIMEOUT_KEY = "connect.timeout"; + + public static final String TIMEOUT_KEY = "timeout"; + + public static final String RETRIES_KEY = "retries"; + + public static final String CODEC_KEY = "codec"; + public static final String DOWNSTREAM_CODEC_KEY = "codec.downstream"; + + public static final String SERIALIZATION_KEY = "serialization"; + + public static final String EXCHANGER_KEY = "exchanger"; + + public static final String TRANSPORTER_KEY = "transporter"; + + public static final String SERVER_KEY = "server"; + + public static final String CLIENT_KEY = "client"; + + public static final String ASYNC_KEY = "async"; + + public static final String TOKEN_KEY = "token"; + + public static final String METHODS_KEY = "methods"; + + public static final String CHARSET_KEY = "charset"; + + public static final String RECONNECT_KEY = "reconnect"; + + public static final String SEND_RECONNECT_KEY = "send.reconnect"; + + public static final int DEFAULT_RECONNECT_PERIOD = 2000; + + public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; + + public static final String CHECK_KEY = "check"; + + public static final String GROUP_KEY = "group"; + + public static final String PATH_KEY = "path"; + + public static final String INTERFACE_KEY = "interface"; + + public static final String GENERIC_KEY = "generic"; + + public static final String FILE_KEY = "file"; + + public static final String WAIT_KEY = "wait"; + + public static final String VERSION_KEY = "version"; + + public static final String REVISION_KEY = "revision"; + + public static final String DUBBO_VERSION_KEY = "dubbo"; + + public static final String HESSIAN_VERSION_KEY = "hessian.version"; + + public static final String CHANNEL_HANDLER_KEY = "channel.handler"; + + public static final String DEFAULT_CHANNEL_HANDLER = "default"; + + + public static final String COMMA_SEPARATOR = ","; + + public static final Pattern COMMA_SPLIT_PATTERN = Pattern.compile("\\s*[,]+\\s*"); + + public static final String REGISTRY_SEPARATOR = "|"; + + public static final Pattern REGISTRY_SPLIT_PATTERN = Pattern.compile("\\s*[|]+\\s*"); + + public static final String SEMICOLON_SEPARATOR = ";"; + + public static final Pattern SEMICOLON_SPLIT_PATTERN = Pattern.compile("\\s*[;]+\\s*"); + + public static final String CONNECT_QUENE_CAPACITY = "connect.quene.capacity"; + + public static final String CONNECT_QUENE_WARNING_SIZE = "connect.quene.warning.size"; + + public static final int DEFAULT_CONNECT_QUENE_WARNING_SIZE = 1000; + + private Constants(){ + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Extension.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Extension.java new file mode 100644 index 0000000000..95ef1e7d82 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Extension.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 扩展点实现的元信息。 + * + * @author william.liangf + * @author ding.lid + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface Extension { + + /** + * 扩展点名称。
+ * + * 如果注解在扩展的接口上,则缺省的扩展点。

+ */ + String value() default ""; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/ExtensionLoader.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/ExtensionLoader.java new file mode 100644 index 0000000000..7b6e1c4015 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/ExtensionLoader.java @@ -0,0 +1,506 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Pattern; + +import com.alibaba.dubbo.common.bytecode.ClassGenerator; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.common.utils.Reference; + +/** + * Dubbo使用的扩展点获取。

+ *

    + *
  • 自动注入关联扩展点。
  • + *
  • 自动Wrap上扩展点的Wrap类。
  • + *
  • 缺省获得的的扩展点是一个Adaptive Instance。 + *
+ * + * @see JDK5.0的自动发现机制实现 + * + * @author liangfei + * @author ding.lid + * + * @see Extension + * @see Adaptive + * @see Autoproxy + */ +public class ExtensionLoader { + + private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class); + + private static final String SERVICES_DIRECTORY = "META-INF/services/"; + + private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*"); + + private static final ConcurrentMap, ExtensionLoader> EXTENSION_LOADERS = new ConcurrentHashMap, ExtensionLoader>(); + + private final Class type; + + private final Reference>> cachedClasses = new Reference>>(); + + private final ConcurrentMap> cachedInstances = new ConcurrentHashMap>(); + + private volatile Class cachedAdaptiveClass = null; + + private final Reference cachedAdaptiveInstance = new Reference(); + + private Set> cachedWrapperClasses; + + private String cachedDefaultName; + + @SuppressWarnings("unchecked") + public static ExtensionLoader getExtensionLoader(Class type) { + if (type == null) + throw new IllegalArgumentException("Extension type == null"); + + ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); + if (loader == null) { + EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); + loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); + } + return loader; + } + + private ExtensionLoader(Class type) { + this.type = type; + } + + @SuppressWarnings("unchecked") + public T getExtension(String name) { + if (name == null || name.length() == 0) + throw new IllegalArgumentException("Extension name == null"); + Reference reference = cachedInstances.get(name); + if (reference == null) { + cachedInstances.putIfAbsent(name, new Reference()); + reference = cachedInstances.get(name); + } + Object instance = reference.get(); + if (instance == null) { + synchronized (reference) { + instance = reference.get(); + if (instance == null) { + instance = createExtension(name); + reference.set(instance); + } + } + } + return (T) instance; + } + + public boolean hasExtension(String name) { + if (name == null || name.length() == 0) + throw new IllegalArgumentException("Extension name == null"); + try { + return getExtensionClass(name) != null; + } catch (Throwable t) { + return false; + } + } + + public Set getSupportedExtensions() { + Map> clazzes = getExtensionClasses(); + return Collections.unmodifiableSet(new TreeSet(clazzes.keySet())); + } + + @SuppressWarnings("unchecked") + public T getAdaptiveExtension() { + Object instance = cachedAdaptiveInstance.get(); + if (instance == null) { + synchronized (cachedAdaptiveInstance) { + instance = cachedAdaptiveInstance.get(); + if (instance == null) { + instance = createAdaptiveExtension(); + cachedAdaptiveInstance.set(instance); + } + } + } + return (T) instance; + } + + @SuppressWarnings("unchecked") + private T createExtension(String name) { + Class clazz = getExtensionClasses().get(name); + if (clazz == null) { + throw new IllegalStateException("No such extension " + type.getName() + " by name " + name); + } + try { + T instance = (T) clazz.newInstance(); + injectExtension(instance); + Set> wrapperClasses = cachedWrapperClasses; + if (wrapperClasses != null && wrapperClasses.size() > 0) { + for (Class wrapperClass : wrapperClasses) { + instance = (T) wrapperClass.getConstructor(type).newInstance(instance); + injectExtension(instance); + } + } + return instance; + } catch (Throwable t) { + throw new IllegalStateException("Extension instance(name: " + name + ", class: " + + type + ") could not be instantiated: " + t.getMessage(), t); + } + } + + private void injectExtension(Object instance) { + try { + for (Method method : instance.getClass().getMethods()) { + if (method.getName().startsWith("set") + && method.getParameterTypes().length == 1 + && Modifier.isPublic(method.getModifiers())) { + Class pt = method.getParameterTypes()[0]; + if (pt.isInterface()) { + try { + Object adaptive = getExtensionLoader(pt).getAdaptiveExtension(); + method.invoke(instance, adaptive); + } catch (Exception e) { + logger.error("fail to inject via method " + method.getName() + + " of interface " + type.getName() + ": " + e.getMessage(), e); + } + } + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + private Class getExtensionClass(String name) { + if (type == null) + throw new IllegalArgumentException("Extension type == null"); + if (name == null) + throw new IllegalArgumentException("Extension name == null"); + Class clazz = getExtensionClasses().get(name); + if (clazz == null) + throw new IllegalStateException("No such extension \"" + name + "\" for " + type.getName() + "!"); + return clazz; + } + + private Map> getExtensionClasses() { + Map> classes = cachedClasses.get(); + if (classes == null) { + synchronized (cachedClasses) { + classes = cachedClasses.get(); + if (classes == null) { + classes = loadExtensionClasses(); + cachedClasses.set(classes); + } + } + } + return classes; + } + + private Map> loadExtensionClasses() { + final Extension defaultAnnotation = type.getAnnotation(Extension.class); + if(defaultAnnotation != null) { + String[] names = NAME_SEPARATOR.split(defaultAnnotation.value()); + if(names.length > 1) { + throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + + ": " + Arrays.toString(names)); + } + if(names.length == 1) cachedDefaultName = names[0]; + } + + ClassLoader classLoader = findClassLoader(); + Map> extensionClasses = new HashMap>(); + String fileName = null; + try { + fileName = SERVICES_DIRECTORY + type.getName(); + Enumeration urls; + if (classLoader != null) { + urls = classLoader.getResources(fileName); + } else { + urls = ClassLoader.getSystemResources(fileName); + } + if (urls != null) { + while (urls.hasMoreElements()) { + java.net.URL url = urls.nextElement(); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); + try { + String line = null; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.length() > 0) { + try { + Class clazz = Class.forName(line, true, classLoader); + if (! type.isAssignableFrom(clazz)) { + throw new IllegalStateException("Error when load extension class(interface: " + + type + ", class line: " + clazz.getName() + "), class " + + clazz.getName() + "is not subtype of interface."); + } + if (clazz.isAnnotationPresent(Adaptive.class)) { + if(cachedAdaptiveClass == null) { + cachedAdaptiveClass = clazz; + } else if (! cachedAdaptiveClass.equals(clazz)) { + throw new IllegalStateException("More than 1 adaptive class found: " + + cachedAdaptiveClass.getClass().getName() + + ", " + clazz.getClass().getName()); + } + } else { + try { + clazz.getConstructor(type); + Set> autoproxies = cachedWrapperClasses; + if (autoproxies == null) { + cachedWrapperClasses = new ConcurrentHashSet>(); + autoproxies = cachedWrapperClasses; + } + autoproxies.add(clazz); + } catch (NoSuchMethodException e) { + clazz.getConstructor(); + Extension extension = clazz.getAnnotation(Extension.class); + if (extension == null) { + throw new IllegalStateException("No such @Extension annotation in class " + type.getName()); + } + String name = extension.value(); + if (name == null || name.length() == 0) { + throw new IllegalStateException("Illegal @Extension annotation in class " + type.getName()); + } + String[] names = NAME_SEPARATOR.split(name); + for (String n : names) { + Class c = extensionClasses.get(n); + if (c == null) { + extensionClasses.put(n, clazz); + } else if (c != clazz) { + throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName()); + } + } + } + } + } catch (Throwable t) { + logger.error("Exception when load extension class(interface: " + + type + ", class line: " + line + ") in " + url, t); + } + } + } // end of while read lines + } finally { + reader.close(); + } + } catch (Throwable t) { + logger.error("Exception when load extension class(interface: " + + type + ", class file: " + url + ") in " + url, t); + } + } // end of while urls + } + } catch (Throwable t) { + logger.error("Exception when load extension class(interface: " + + type + ", description file: " + fileName + ").", t); + } + return extensionClasses; + } + + @SuppressWarnings("unchecked") + private T createAdaptiveExtension() { + try { + return (T) getAdaptiveExtensionClass().newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e); + } + } + + private Class getAdaptiveExtensionClass() { + getExtensionClasses(); + if (cachedAdaptiveClass != null) { + return cachedAdaptiveClass; + } + return cachedAdaptiveClass = createAdaptiveExtensionClass(); + } + + private Class createAdaptiveExtensionClass() { + ClassLoader classLoader = findClassLoader(); + + Method[] methods = type.getMethods(); + boolean hasAdaptiveAnnotation = false; + for(Method m : methods) { + if(m.isAnnotationPresent(Adaptive.class)) { + hasAdaptiveAnnotation = true; + break; + } + } + // 完全没有Adaptive方法,则不需要生成Adaptive类 + if(! hasAdaptiveAnnotation) + throw new IllegalStateException("No such adaptive class for extension " + type.getName()); + + ClassGenerator cg = ClassGenerator.newInstance(classLoader); + cg.setClassName(type.getName() + "$Adpative"); + cg.addInterface(type); + cg.addDefaultConstructor(); + + for (Method method : methods) { + Class rt = method.getReturnType(); + Class[] pts = method.getParameterTypes(); + + Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); + StringBuilder code = new StringBuilder(512); + if (adaptiveAnnotation == null) { + code.append("throw new UnsupportedOperationException(\"method ") + .append(method.toString()).append(" of interface ") + .append(type.getName()).append(" is not adaptive method!\");"); + } else { + int urlTypeIndex = -1; + for (int i = 0; i < pts.length; ++i) { + if (pts[i].equals(URL.class)) { + urlTypeIndex = i; + break; + } + } + // 有类型为URL的参数 + if (urlTypeIndex != -1) { + // Null Point check + String s = String.format("if (arg%d == null) { throw new IllegalArgumentException(\"url == null\"); }", + urlTypeIndex); + code.append(s); + + s = String.format("%s url = arg%d;", URL.class.getName(), urlTypeIndex); + code.append(s); + } + // 参数没有URL类型 + else { + String attribMethod = null; + + // 找到参数的URL属性 + LBL_PTS: + for (int i = 0; i < pts.length; ++i) { + Method[] ms = pts[i].getMethods(); + for (Method m : ms) { + String name = m.getName(); + if ((name.startsWith("get") || name.length() > 3) + && Modifier.isPublic(m.getModifiers()) + && !Modifier.isStatic(m.getModifiers()) + && m.getParameterTypes().length == 0 + && m.getReturnType() == URL.class) { + urlTypeIndex = i; + attribMethod = name; + break LBL_PTS; + } + } + } + if(attribMethod == null) { + throw new IllegalStateException("fail to create adative class for interface " + type.getName() + + ": not found url parameter or url attribute in parameters of method " + method.getName()); + } + + // Null point check + String s = String.format("if (arg%d == null) { throw new IllegalArgumentException(\"%s argument == null\"); }", + urlTypeIndex, pts[urlTypeIndex].getName()); + code.append(s); + s = String.format("if (arg%d.%s() == null) { throw new IllegalArgumentException(\"%s argument %s() == null\"); }", + urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod); + code.append(s); + + s = String.format("%s url = arg%d.%s();",URL.class.getName(), urlTypeIndex, attribMethod); + code.append(s); + } + + String[] value = adaptiveAnnotation.value(); + // 没有设置Key,则使用“扩展点接口名的点分隔 作为Key + if(value.length == 0) { + char[] charArray = type.getSimpleName().toCharArray(); + StringBuilder sb = new StringBuilder(128); + for (int i = 0; i < charArray.length; i++) { + if(Character.isUpperCase(charArray[i])) { + if(i != 0) { + sb.append("."); + } + sb.append(Character.toLowerCase(charArray[i])); + } + else { + sb.append(charArray[i]); + } + } + value = new String[] {sb.toString()}; + } + + String defaultExtName = cachedDefaultName; + String getNameCode = null; + for (int i = value.length - 1; i >= 0; --i) { + if(i == value.length - 1) { + if(null != defaultExtName) { + if(!"protocol".equals(value[i])) + getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName); + else + getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName); + } + else { + if(!"protocol".equals(value[i])) + getNameCode = String.format("url.getParameter(\"%s\")", value[i]); + else + getNameCode = "url.getProtocol()"; + } + } + else { + if(!"protocol".equals(value[i])) + getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode); + else + getNameCode = String.format("( url.getProtocol() == null ? (%s) : url.getProtocol() )", getNameCode); + } + } + code.append("String extName = ").append(getNameCode).append(";"); + // check extName == null? + String s = String.format("if(extName == null) {" + + "throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\"); }", + type.getName(), Arrays.toString(value)); + code.append(s); + + s = String.format("%s extension = (% + *
  • http://www.facebook.com/friends?param=value1 + *
  • http://username:password@10.20.130.230:8080/list?version=1.0.0 + *
  • registry://192.168.1.7:9090/com.alibaba.service1?param1=value1¶m2=value2 + *
  • ftp://username:password@192.168.1.7:21/1/read.txt + *
  • file:///home/user1/router.js?type=script
    + * for this case, url protocol = null, url host = null, url path = /home/user1/router.js + *
  • file:///D:/1/router.js?type=script
    + * for this case, url protocol = null, url host = null, url path = /D:/1/router.js + * + * + * @author william.liangf + * @author ding.lid + */ +public final class URL implements Serializable { + + private static final long serialVersionUID = -1985165475234910535L; + + private final String protocol; + + private final String username; + + private final String password; + + private final String host; + + private final int port; + + private final String path; + + private final Map parameters; + + protected URL() { + this.protocol = null; + this.username = null; + this.password = null; + this.host = null; + this.port = 0; + this.path = null; + this.parameters = null; + } + + public URL(String protocol, String host, int port) { + this(protocol, null, null, host, port, null, (Map) null); + } + + public URL(String protocol, String host, int port, String... pairs) { + this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs)); + } + + public URL(String protocol, String host, int port, Map parameters) { + this(protocol, null, null, host, port, null, parameters); + } + + public URL(String protocol, String host, int port, String path) { + this(protocol, null, null, host, port, path, (Map) null); + } + + public URL(String protocol, String host, int port, String path, String... pairs) { + this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs)); + } + + public URL(String protocol, String host, int port, String path, Map parameters) { + this(protocol, null, null, host, port, path, parameters); + } + + public URL(String protocol, String username, String password, String host, int port, String path) { + this(protocol, username, password, host, port, path, (Map) null); + } + + public URL(String protocol, String username, String password, String host, int port, String path, String... pairs) { + this(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs)); + } + + public URL(String protocol, String username, String password, String host, int port, String path, Map parameters) { + if ((username == null || username.length() == 0) + && password != null && password.length() > 0) { + throw new IllegalArgumentException("Invalid url, password without username!"); + } + this.protocol = protocol; + this.username = username; + this.password = password; + this.host = host; + this.port = (port < 0 ? 0 : port); + this.path = path; + // trim the beginning "/" + while(path != null && path.startsWith("/")) { + path = path.substring(1); + } + this.parameters = Collections.unmodifiableMap(parameters != null ? new HashMap(parameters) : new HashMap(0)); + } + + public String getProtocol() { + return protocol; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public String getAddress() { + return port <= 0 ? host : host + ":" + port; + } + + public InetSocketAddress getInetSocketAddress() { + return new InetSocketAddress(host, port); + } + + public String getPath() { + return path; + } + + public String getAbsolutePath() { + if(path != null && !path.startsWith("/")) { + return "/" + path; + } + return path; + } + + public URL setProtocol(String protocol) { + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL setUsername(String username) { + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL setPassword(String password) { + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL setAddress(String address) { + int i = address.lastIndexOf(':'); + String host; + int port = this.port; + if (i >= 0) { + host = address.substring(0, i); + port = Integer.parseInt(address.substring(i + 1)); + } else { + host = address; + } + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL setHost(String host) { + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL setPort(int port) { + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL setPath(String path) { + return new URL(protocol, username, password, host, port, path, getParameters()); + } + + public URL addParameterAndEncoded(String key, String value) { + try { + value = URLEncoder.encode(value, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + return addParameter(key, value); + } + + public URL addParameter(String key, boolean value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, char value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, byte value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, short value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, int value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, long value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, float value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, double value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, Enum value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, Number value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, CharSequence value) { + return addParameter(key, String.valueOf(value)); + } + + public URL addParameter(String key, String value) { + if (key == null || key.length() == 0 + || value == null || value.length() == 0) { + return this; + } + Map map = new HashMap(getParameters()); + map.put(key, value); + return new URL(protocol, username, password, host, port, path, map); + } + + public URL addParameterIfAbsent(String key, Object value) { + if (key == null || key.length() == 0 + || value == null || String.valueOf(value).length() == 0) { + return this; + } + if (hasParameter(key)) { + return this; + } + Map map = new HashMap(getParameters()); + map.put(key, String.valueOf(value)); + return new URL(protocol, username, password, host, port, path, map); + } + + /** + * Add parameters to a new url. + * + * @param parameters + * @return A new URL + */ + public URL addParameters(Map parameters) { + if (parameters == null || parameters.size() == 0) { + return this; + } + Map map = new HashMap(getParameters()); + map.putAll(parameters); + return new URL(protocol, username, password, host, port, path, map); + } + + public URL addParametersIfAbsent(Map parameters) { + if (parameters == null || parameters.size() == 0) { + return this; + } + Map map = new HashMap(parameters); + map.putAll(getParameters()); + return new URL(protocol, username, password, host, port, path, map); + } + + public URL addParameters(String... pairs) { + if (pairs == null || pairs.length == 0) { + return this; + } + if (pairs.length % 2 != 0) { + throw new IllegalArgumentException("Map pairs can not be odd number."); + } + Map map = new HashMap(); + int len = pairs.length / 2; + for (int i = 0; i < len; i ++) { + map.put(pairs[2 * i], pairs[2 * i + 1]); + } + return addParameters(map); + } + + public URL removeParameter(String key) { + if (key == null || key.length() == 0) { + return this; + } + return removeParameters(key); + } + + public URL removeParameters(Collection keys) { + if (keys == null || keys.size() == 0) { + return this; + } + return removeParameters(keys.toArray(new String[0])); + } + + public URL removeParameters(String... keys) { + if (keys == null || keys.length == 0) { + return this; + } + Map map = new HashMap(getParameters()); + for (String key : keys) { + map.remove(key); + } + if (map.size() == getParameters().size()) { + return this; + } + return new URL(protocol, username, password, host, port, path, map); + } + + public URL cleatParameters() { + return new URL(protocol, username, password, host, port, path, new HashMap()); + } + + /** + * Parse url string + * + * @param url URL string + * @return URL instance + */ + public static URL valueOf(String url) { + if (url == null || (url = url.trim()).length() == 0) { + throw new IllegalArgumentException("url == null"); + } + String protocol = null; + String username = null; + String password = null; + String host = null; + int port = 0; + String path = null; + Map parameters = null; + int i = url.indexOf("?"); // seperator between body and parameters + if (i >= 0) { + String[] parts = url.substring(i + 1).split("\\&"); + parameters = new HashMap(); + for (String part : parts) { + part = part.trim(); + if (part.length() > 0) { + int j = part.indexOf('='); + if (j >= 0) { + parameters.put(part.substring(0, j), part.substring(j + 1)); + } else { + parameters.put(part, part); + } + } + } + url = url.substring(0, i); + } + i = url.indexOf("://"); + if (i >= 0) { + if(i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\""); + protocol = url.substring(0, i); + url = url.substring(i + 3); + } + else { + // case: file:/path/to/file.txt + i = url.indexOf(":/"); + if(i>=0) { + if(i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\""); + protocol = url.substring(0, i); + url = url.substring(i + 1); + } + } + + i = url.indexOf("/"); + if (i >= 0) { + path = url.substring(i + 1); + url = url.substring(0, i); + } + i = url.indexOf("@"); + if (i >= 0) { + username = url.substring(0, i); + int j = username.indexOf(":"); + if (j >= 0) { + password = username.substring(j + 1); + username = username.substring(0, j); + } + url = url.substring(i + 1); + } + i = url.indexOf(":"); + if (i >= 0 && i < url.length() - 1) { + port = Integer.parseInt(url.substring(i + 1)); + url = url.substring(0, i); + } + if(url.length() > 0) host = url; + return new URL(protocol, username, password, host, port, path, parameters); + } + + public String toIdentityString() { + return buildString(false, false); // only return identity message, see the method "equals" and "hashCode" + } + + public String toFullString() { + return buildString(true, true); + } + + public String toParameterString() { + StringBuilder buf = new StringBuilder(); + if (getParameters().size() > 0) { + boolean first = true; + for (Map.Entry entry : getParameters().entrySet()) { + if (entry.getKey() != null && entry.getKey().length() > 0) { + if (first) { + first = false; + } else { + buf.append("&"); + } + buf.append(entry.getKey()); + buf.append("="); + buf.append(entry.getValue() == null ? "" : entry.getValue().trim()); + } + } + } + return buf.toString(); + } + + public java.net.URL toJavaURL() { + try { + return new java.net.URL(toString()); + } catch (MalformedURLException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + public String toString() { + return buildString(false, true); // no show username and password + } + + private String buildString(boolean u, boolean p) { + StringBuilder buf = new StringBuilder(); + if (protocol != null && protocol.length() > 0) { + buf.append(protocol); + buf.append("://"); + } + if (u && username != null && username.length() > 0) { + buf.append(username); + if (password != null && password.length() > 0) { + buf.append(":"); + buf.append(password); + } + buf.append("@"); + } + if(host != null && host.length() > 0) { + buf.append(host); + if (port > 0) { + buf.append(":"); + buf.append(port); + } + } + if (path != null && path.length() > 0) { + buf.append("/"); + buf.append(path); + } + if (p) { + if (getParameters().size() > 0) { + boolean first = true; + for (Map.Entry entry : new TreeMap(getParameters()).entrySet()) { + if (entry.getKey() != null && entry.getKey().length() > 0) { + if (first) { + buf.append("?"); + first = false; + } else { + buf.append("&"); + } + buf.append(entry.getKey()); + buf.append("="); + buf.append(entry.getValue() == null ? "" : entry.getValue().trim()); + } + } + } + } + return buf.toString(); + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((host == null) ? 0 : host.hashCode()); + result = prime * result + ((path == null) ? 0 : path.hashCode()); + result = prime * result + port; + result = prime * result + + ((protocol == null) ? 0 : protocol.hashCode()); + return result; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + URL other = (URL) obj; + if (host == null) { + if (other.host != null) + return false; + } else if (!host.equals(other.host)) + return false; + if (path == null) { + if (other.path != null) + return false; + } else if (!path.equals(other.path)) + return false; + if (port != other.port) + return false; + if (protocol == null) { + if (other.protocol != null) + return false; + } else if (!protocol.equals(other.protocol)) + return false; + return true; + } + + public String getServiceKey() { + StringBuilder buf = new StringBuilder(); + String group = getParameter(Constants.GROUP_KEY); + if (group != null && group.length()>0){ + buf.append(group).append("/"); + } + buf.append(getParameter(Constants.INTERFACE_KEY, path)); + String version = getParameter(Constants.VERSION_KEY); + if (version!= null && version.length()>0){ + buf.append(":").append(version); + } + return buf.toString(); + } + + public Map getParameters() { + return parameters; + } + + public String getParameterAndDecoded(String key) { + return getParameterAndDecoded(key, null); + } + + public String getParameterAndDecoded(String key, String defaultValue) { + String value = getParameter(key, defaultValue); + if (value != null && value.length() > 0) { + try { + value = URLDecoder.decode(value, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + return value; + } + + public String getParameter(String key) { + String value = parameters.get(key); + if (value == null || value.length() == 0) { + value = parameters.get(Constants.HIDE_KEY_PREFIX + key); + } + if (value == null || value.length() == 0) { + value = parameters.get(Constants.DEFAULT_KEY_PREFIX + key); + } + if (value == null || value.length() == 0) { + value = parameters.get(Constants.HIDE_KEY_PREFIX + Constants.DEFAULT_KEY_PREFIX + key); + } + return value; + } + + public String getParameter(String key, String defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return value; + } + + public float getFloatParameter(String key) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return 0; + } + return Float.parseFloat(value); + } + + public float getLongParameter(String key, float defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Float.parseFloat(value); + } + + public double getDoubleParameter(String key) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return 0; + } + return Double.parseDouble(value); + } + + public double getDoubleParameter(String key, double defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Double.parseDouble(value); + } + + public long getLongParameter(String key) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return 0; + } + return Long.parseLong(value); + } + + public long getLongParameter(String key, long defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Long.parseLong(value); + } + + public int getIntParameter(String key) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return 0; + } + return Integer.parseInt(value); + } + + public int getIntParameter(String key, int defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Integer.parseInt(value); + } + + public int getPositiveIntParameter(String key, int defaultValue) { + if (defaultValue <= 0) { + throw new IllegalArgumentException("defaultValue <= 0"); + } + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + int i = Integer.parseInt(value); + if (i > 0) { + return i; + } + return defaultValue; + } + + public boolean getBooleanParameter(String key) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return false; + } + return Boolean.parseBoolean(value); + } + + public boolean getBooleanParameter(String key, boolean defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Boolean.parseBoolean(value); + } + + public boolean hasParameter(String key) { + String value = getParameter(key); + return value != null && value.length() > 0; + } + + public String getMethodParameter(String method, String key) { + String value = parameters.get(method + "." + key); + if (value == null || value.length() == 0) { + value = parameters.get(Constants.HIDE_KEY_PREFIX + method + "." + key); + } + if (value == null || value.length() == 0) { + return getParameter(key); + } + return value; + } + + public String getMethodParameter(String method, String key, String defaultValue) { + String value = getMethodParameter(method, key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return value; + } + + public int getMethodIntParameter(String method, String key) { + String value = getMethodParameter(method, key); + if (value == null || value.length() == 0) { + return 0; + } + return Integer.parseInt(value); + } + + public int getMethodIntParameter(String method, String key, int defaultValue) { + String value = getMethodParameter(method, key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Integer.parseInt(value); + } + + public int getMethodPositiveIntParameter(String method, String key, int defaultValue) { + if (defaultValue <= 0) { + throw new IllegalArgumentException("defaultValue <= 0"); + } + String value = getMethodParameter(method, key); + if (value == null || value.length() == 0) { + return defaultValue; + } + int i = Integer.parseInt(value); + if (i > 0) { + return i; + } + return defaultValue; + } + + public boolean getMethodBooleanParameter(String method, String key) { + String value = getMethodParameter(method, key); + if (value == null || value.length() == 0) { + return false; + } + return Boolean.parseBoolean(value); + } + + public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) { + String value = getMethodParameter(method, key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return Boolean.parseBoolean(value); + } + + public boolean hasMethodParamter(String method, String key) { + String value = getMethodParameter(method, key); + return value != null && value.length() > 0; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java new file mode 100644 index 0000000000..5e07b9640b --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Version.java @@ -0,0 +1,135 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import java.net.URL; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +/** + * Version + * + * @author william.liangf + */ +public final class Version { + + private Version() {} + + private static final Logger logger = LoggerFactory.getLogger(Version.class); + + private static final String VERSION = getVersion(Version.class, "2.0.0"); + + private static final boolean INTERNAL = hasResource("com/alibaba/dubbo/registry/support/remote/RemoteRegistry.class"); + + private static final boolean COMPATIBLE = hasResource("com/alibaba/dubbo/rpc/dubbo/internal/DubboRequest.class"); + + static { + // 检查是否存在重复的jar包 + Version.checkDuplicate(Version.class); + } + + public static String getVersion(){ + return VERSION; + } + + public static boolean isInternalVersion() { + return INTERNAL; + } + + public static boolean isCompatibleVersion() { + return COMPATIBLE; + } + + public static boolean hasResource(String path) { + try { + return Version.class.getClassLoader().getResource(path) != null; + } catch (Throwable t) { + return false; + } + } + + public static String getVersion(Class cls, String defaultVersion) { + try { + // 首先查找MANIFEST.MF规范中的版本号 + String version = cls.getPackage().getImplementationVersion(); + if (version == null || version.length() == 0) { + version = cls.getPackage().getSpecificationVersion(); + } + if (version == null || version.length() == 0) { + // 如果规范中没有版本号,基于jar包名获取版本号 + String file = cls.getProtectionDomain().getCodeSource().getLocation().getFile(); + if (file != null && file.length() > 0 && file.endsWith(".jar")) { + file = file.substring(0, file.length() - 4); + int i = file.lastIndexOf('/'); + if (i >= 0) { + file = file.substring(i + 1); + } + i = file.indexOf("-"); + if (i >= 0) { + file = file.substring(i + 1); + } + while (file.length() > 0 && ! Character.isDigit(file.charAt(0))) { + i = file.indexOf("-"); + if (i >= 0) { + file = file.substring(i + 1); + } else { + break; + } + } + version = file; + } + } + // 返回版本号,如果为空返回缺省版本号 + return version == null || version.length() == 0 ? defaultVersion : version; + } catch (Throwable e) { // 防御性容错 + // 忽略异常,返回缺省版本号 + logger.error(e.getMessage(), e); + return defaultVersion; + } + } + + public static void checkDuplicate(Class cls) { + checkDuplicate(cls.getName().replace('.', '/') + ".class"); + } + + public static void checkDuplicate(String path) { + try { + // 在ClassPath搜文件 + Enumeration urls = Thread.currentThread().getContextClassLoader().getResources(path); + Set files = new HashSet(); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + if (url != null) { + String file = url.getFile(); + if (file != null && file.length() > 0) { + files.add(file); + } + } + } + // 如果有多个,就表示重复 + if (files.size() > 1) { + logger.error("Duplicate class " + path + " in " + files.size() + " jar " + files); + } + } catch (Throwable e) { // 防御性容错 + logger.error(e.getMessage(), e); + } + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/ClassGenerator.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/ClassGenerator.java new file mode 100644 index 0000000000..8371230132 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/ClassGenerator.java @@ -0,0 +1,382 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.bytecode; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtField; +import javassist.CtMethod; +import javassist.CtNewConstructor; +import javassist.CtNewMethod; +import javassist.LoaderClassPath; +import javassist.NotFoundException; + +import com.alibaba.dubbo.common.utils.ReflectUtils; + +/** + * ClassGenerator + * + * @author qian.lei + */ + +public final class ClassGenerator +{ + public static interface DC{} // dynamic class tag interface. + + private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(0); + + private static final String SIMPLE_NAME_TAG = ""; + + private static final Map POOL_MAP = new ConcurrentHashMap(); //ClassLoader - ClassPool + + public static ClassGenerator newInstance() + { + return new ClassGenerator(getClassPool(null)); + } + + public static ClassGenerator newInstance(ClassLoader loader) + { + return new ClassGenerator(getClassPool(loader)); + } + + public static boolean isDynamicClass(Class cl) + { + return ClassGenerator.DC.class.isAssignableFrom(cl); + } + + private static ClassPool getClassPool(ClassLoader loader) + { + if( loader == null ) + return ClassPool.getDefault(); + + ClassPool pool = POOL_MAP.get(loader); + if( pool == null ) + { + pool = new ClassPool(true); + pool.appendClassPath(new LoaderClassPath(loader)); + POOL_MAP.put(loader, pool); + } + return pool; + } + + private ClassPool mPool; + + private CtClass mCtc; + + private String mClassName, mSuperClass; + + private Set mInterfaces; + + private List mFields, mConstructors, mMethods; + + private Map mCopyMethods; // + + private Map> mCopyConstructors; // + + private boolean mDefaultConstructor = false; + + private ClassGenerator(){} + + private ClassGenerator(ClassPool pool) + { + mPool = pool; + } + + public String getClassName() + { + return mClassName; + } + + public ClassGenerator setClassName(String name) + { + mClassName = name; + return this; + } + + public ClassGenerator addInterface(String cn) + { + if( mInterfaces == null ) + mInterfaces = new HashSet(); + mInterfaces.add(cn); + return this; + } + + public ClassGenerator addInterface(Class cl) + { + return addInterface(cl.getName()); + } + + public ClassGenerator setSuperClass(String cn) + { + mSuperClass = cn; + return this; + } + + public ClassGenerator setSuperClass(Class cl) + { + mSuperClass = cl.getName(); + return this; + } + + public ClassGenerator addField(String code) + { + if( mFields == null ) + mFields = new ArrayList(); + mFields.add(code); + return this; + } + + public ClassGenerator addField(String name, int mod, Class type) + { + return addField(name, mod, type, null); + } + + public ClassGenerator addField(String name, int mod, Class type, String def) + { + StringBuilder sb = new StringBuilder(); + sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(type)).append(' '); + sb.append(name); + if( def != null && def.length() > 0 ) + { + sb.append('='); + sb.append(def); + } + sb.append(';'); + return addField(sb.toString()); + } + + public ClassGenerator addMethod(String code) + { + if( mMethods == null ) + mMethods = new ArrayList(); + mMethods.add(code); + return this; + } + + public ClassGenerator addMethod(String name, int mod, Class rt, Class[] pts, String body) + { + return addMethod(name, mod, rt, pts, null, body); + } + + public ClassGenerator addMethod(String name, int mod, Class rt, Class[] pts, Class[] ets, String body) + { + StringBuilder sb = new StringBuilder(); + sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(rt)).append(' ').append(name); + sb.append('('); + for(int i=0;i 0 ) + sb.append(','); + sb.append(ReflectUtils.getName(pts[i])); + sb.append(" arg").append(i); + } + sb.append(')'); + if( ets != null && ets.length > 0 ) + { + sb.append(" throws "); + for(int i=0;i 0 ) + sb.append(','); + sb.append(ReflectUtils.getName(ets[i])); + } + } + sb.append('{').append(body).append('}'); + return addMethod(sb.toString()); + } + + public ClassGenerator addMethod(Method m) + { + addMethod(m.getName(), m); + return this; + } + + public ClassGenerator addMethod(String name, Method m) + { + String desc = name + ReflectUtils.getDescWithoutMethodName(m); + addMethod(':' + desc); + if( mCopyMethods == null ) + mCopyMethods = new ConcurrentHashMap(8); + mCopyMethods.put(desc, m); + return this; + } + + public ClassGenerator addConstructor(String code) + { + if( mConstructors == null ) + mConstructors = new LinkedList(); + mConstructors.add(code); + return this; + } + + public ClassGenerator addConstructor(int mod, Class[] pts, String body) + { + return addConstructor(mod, pts, null, body); + } + + public ClassGenerator addConstructor(int mod, Class[] pts, Class[] ets, String body) + { + StringBuilder sb = new StringBuilder(); + sb.append(modifier(mod)).append(' ').append(SIMPLE_NAME_TAG); + sb.append('('); + for(int i=0;i 0 ) + sb.append(','); + sb.append(ReflectUtils.getName(pts[i])); + sb.append(" arg").append(i); + } + sb.append(')'); + if( ets != null && ets.length > 0 ) + { + sb.append(" throws "); + for(int i=0;i 0 ) + sb.append(','); + sb.append(ReflectUtils.getName(ets[i])); + } + } + sb.append('{').append(body).append('}'); + return addConstructor(sb.toString()); + } + + public ClassGenerator addConstructor(Constructor c) + { + String desc = ReflectUtils.getDesc(c); + addConstructor(":"+desc); + if( mCopyConstructors == null ) + mCopyConstructors = new ConcurrentHashMap>(4); + mCopyConstructors.put(desc, c); + return this; + } + + public ClassGenerator addDefaultConstructor() + { + mDefaultConstructor = true; + return this; + } + + public Class toClass() + { + if( mCtc != null ) + mCtc.detach(); + long id = CLASS_NAME_COUNTER.getAndIncrement(); + try + { + CtClass ctcs = mSuperClass == null ? null : mPool.get(mSuperClass); + if( mClassName == null ) + mClassName = ( mSuperClass == null || javassist.Modifier.isPublic(ctcs.getModifiers()) + ? ClassGenerator.class.getName() : mSuperClass + "$sc" ) + id; + mCtc = mPool.makeClass(mClassName); + if( mSuperClass != null ) + mCtc.setSuperclass(ctcs); + mCtc.addInterface(mPool.get(DC.class.getName())); // add dynamic class tag. + if( mInterfaces != null ) + for( String cl : mInterfaces ) mCtc.addInterface(mPool.get(cl)); + if( mFields != null ) + for( String code : mFields ) mCtc.addField(CtField.make(code, mCtc)); + if( mMethods != null ) + { + for( String code : mMethods ) + { + if( code.charAt(0) == ':' ) + mCtc.addMethod(CtNewMethod.copy(getCtMethod(mCopyMethods.get(code.substring(1))), code.substring(1, code.indexOf('(')), mCtc, null)); + else + mCtc.addMethod(CtNewMethod.make(code, mCtc)); + } + } + if( mDefaultConstructor ) + mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc)); + if( mConstructors != null ) + { + for( String code : mConstructors ) + { + if( code.charAt(0) == ':' ) + { + mCtc.addConstructor(CtNewConstructor.copy(getCtConstructor(mCopyConstructors.get(code.substring(1))), mCtc, null)); + } + else + { + String[] sn = mCtc.getSimpleName().split("\\$+"); // inner class name include $. + mCtc.addConstructor(CtNewConstructor.make(code.replaceFirst(SIMPLE_NAME_TAG, sn[sn.length-1]), mCtc)); + } + } + } + return mCtc.toClass(); + } + catch(RuntimeException e) + { + throw e; + } + catch(NotFoundException e) + { + throw new RuntimeException(e.getMessage(), e); + } + catch(CannotCompileException e) + { + throw new RuntimeException(e.getMessage(), e); + } + } + + public void release() + { + if( mCtc != null ) mCtc.detach(); + if( mInterfaces != null ) mInterfaces.clear(); + if( mFields != null ) mFields.clear(); + if( mMethods != null ) mMethods.clear(); + if( mConstructors != null ) mConstructors.clear(); + if( mCopyMethods != null ) mCopyMethods.clear(); + if( mCopyConstructors != null ) mCopyConstructors.clear(); + } + + private CtClass getCtClass(Class c) throws NotFoundException + { + return mPool.get(c.getName()); + } + + private CtMethod getCtMethod(Method m) throws NotFoundException + { + return getCtClass(m.getDeclaringClass()).getMethod(m.getName(),ReflectUtils.getDescWithoutMethodName(m)); + } + + private CtConstructor getCtConstructor(Constructor c) throws NotFoundException + { + return getCtClass(c.getDeclaringClass()).getConstructor(ReflectUtils.getDesc(c)); + } + + private static String modifier(int mod) + { + if( Modifier.isPublic(mod) ) return "public"; + if( Modifier.isProtected(mod) ) return "protected"; + if( Modifier.isPrivate(mod) ) return "private"; + return ""; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/Mixin.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/Mixin.java new file mode 100644 index 0000000000..751a662030 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/Mixin.java @@ -0,0 +1,241 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.bytecode; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +import com.alibaba.dubbo.common.utils.ClassHelper; +import com.alibaba.dubbo.common.utils.ReflectUtils; + +/** + * Mixin + * + * @author qian.lei + */ + +public abstract class Mixin +{ + private static AtomicLong MIXIN_CLASS_COUNTER = new AtomicLong(0); + + private static final String PACKAGE_NAME = Mixin.class.getPackage().getName(); + + public static interface MixinAware{ void setMixinInstance(Object instance); } + + /** + * mixin interface and delegates. + * all class must be public. + * + * @param ics interface class array. + * @param dc delegate class. + * @return Mixin instance. + */ + public static Mixin mixin(Class[] ics, Class dc) + { + return mixin(ics, new Class[]{dc}); + } + + /** + * mixin interface and delegates. + * all class must be public. + * + * @param ics interface class array. + * @param dc delegate class. + * @param cl class loader. + * @return Mixin instance. + */ + public static Mixin mixin(Class[] ics, Class dc, ClassLoader cl) + { + return mixin(ics, new Class[]{dc}, cl); + } + + /** + * mixin interface and delegates. + * all class must be public. + * + * @param ics interface class array. + * @param dcs delegate class array. + * @return Mixin instance. + */ + public static Mixin mixin(Class[] ics, Class[] dcs) + { + return mixin(ics, dcs, ClassHelper.getClassLoader(ics[0])); + } + + /** + * mixin interface and delegates. + * all class must be public. + * + * @param ics interface class array. + * @param dcs delegate class array. + * @param cl class loader. + * @return Mixin instance. + */ + public static Mixin mixin(Class[] ics, Class[] dcs, ClassLoader cl) + { + assertInterfaceArray(ics); + + long id = MIXIN_CLASS_COUNTER.getAndIncrement(); + String pkg = null; + ClassGenerator ccp = null, ccm = null; + try + { + ccp = ClassGenerator.newInstance(cl); + + // impl constructor + StringBuilder code = new StringBuilder(); + for(int i=0;i[]{ Object[].class }, code.toString()); + + // impl methods. + Set worked = new HashSet(); + for(int i=0;i rt = method.getReturnType(); + String mn = method.getName(); + if( Void.TYPE.equals(rt) ) + ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(), + "d" + ix + "." + mn + "($$);"); + else + ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(), + "return ($r)d" + ix + "." + mn + "($$);"); + } + } + + if( pkg == null ) + pkg = PACKAGE_NAME; + + // create MixinInstance class. + String micn = pkg + ".mixin" + id; + ccp.setClassName(micn); + ccp.toClass(); + + // create Mixin class. + String fcn = Mixin.class.getName() + id; + ccm = ClassGenerator.newInstance(cl); + ccm.setClassName(fcn); + ccm.addDefaultConstructor(); + ccm.setSuperClass(Mixin.class.getName()); + ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }"); + Class mixin = ccm.toClass(); + return (Mixin)mixin.newInstance(); + } + catch(RuntimeException e) + { + throw e; + } + catch(Exception e) + { + throw new RuntimeException(e.getMessage(), e); + } + finally + { + // release ClassGenerator + if( ccp != null ) + ccp.release(); + if( ccm != null ) + ccm.release(); + } + } + + /** + * new Mixin instance. + * + * @param ds delegates instance. + * @return instance. + */ + abstract public Object newInstance(Object[] ds); + + protected Mixin(){} + + private static int findMethod(Class[] dcs, String desc) + { + Class cl; + Method[] methods; + for(int i=0;i[] ics) + { + for(int i=0;i> ProxyCacheMap = new WeakHashMap>(); + + private static final Object PendingGenerationMarker = new Object(); + + /** + * Get proxy. + * + * @param ics interface class array. + * @return Proxy instance. + */ + public static Proxy getProxy(Class... ics) + { + return getProxy(ClassHelper.getClassLoader(ics[0]), ics); + } + + /** + * Get proxy. + * @param cl class loader. + * @param ics interface class array. + * + * @return Proxy instance. + */ + public static Proxy getProxy(ClassLoader cl, Class... ics) + { + if( ics.length > 65535 ) + throw new IllegalArgumentException("interface limit exceeded"); + + StringBuilder sb = new StringBuilder(); + for(int i=0;i tmp = null; + try + { + tmp = Class.forName(itf, false, cl); + } + catch(ClassNotFoundException e) + {} + + if( tmp != ics[i] ) + throw new IllegalArgumentException(ics[i] + " is not visible from class loader"); + + sb.append(itf).append(';'); + } + + // use interface class name list as key. + String key = sb.toString(); + + // get cache by class loader. + Map cache; + synchronized( ProxyCacheMap ) + { + cache = ProxyCacheMap.get(cl); + if( cache == null ) + { + cache = new HashMap(); + ProxyCacheMap.put(cl, cache); + } + } + + Proxy proxy = null; + synchronized( cache ) + { + do + { + Object value = cache.get(key); + if( value instanceof Reference ) + { + proxy = (Proxy)((Reference)value).get(); + if( proxy != null ) + return proxy; + } + + if( value == PendingGenerationMarker ) + { + try{ cache.wait(); }catch(InterruptedException e){} + } + else + { + cache.put(key, PendingGenerationMarker); + break; + } + } + while( true ); + } + + long id = PROXY_CLASS_COUNTER.getAndIncrement(); + String pkg = null; + ClassGenerator ccp = null, ccm = null; + try + { + ccp = ClassGenerator.newInstance(cl); + + Set worked = new HashSet(); + List methods = new ArrayList(); + + for(int i=0;i rt = method.getReturnType(); + Class[] pts = method.getParameterTypes(); + + StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];"); + for(int j=0;j[]{ InvocationHandler.class }, new Class[0], "handler=$1;"); + Class clazz = ccp.toClass(); + clazz.getField("methods").set(null, methods.toArray(new Method[0])); + + // create Proxy class. + String fcn = Proxy.class.getName() + id; + ccm = ClassGenerator.newInstance(cl); + ccm.setClassName(fcn); + ccm.addDefaultConstructor(); + ccm.setSuperClass(Proxy.class); + ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }"); + Class pc = ccm.toClass(); + proxy = (Proxy)pc.newInstance(); + } + catch(RuntimeException e) + { + throw e; + } + catch(Exception e) + { + throw new RuntimeException(e.getMessage(), e); + } + finally + { + // release ClassGenerator + if( ccp != null ) + ccp.release(); + if( ccm != null ) + ccm.release(); + synchronized( cache ) + { + if( proxy == null ) + cache.remove(key); + else + cache.put(key, new WeakReference(proxy)); + cache.notifyAll(); + } + } + return proxy; + } + + /** + * get instance with default handler. + * + * @return instance. + */ + public Object newInstance() + { + return newInstance(THROW_UNSUPPORTED_INVOKER); + } + + /** + * get instance with special handler. + * + * @return instance. + */ + abstract public Object newInstance(InvocationHandler handler); + + protected Proxy(){} + + private static String asArgument(Class cl, String name) + { + if( cl.isPrimitive() ) + { + if( Boolean.TYPE == cl ) + return name + "==null?false:((Boolean)" + name + ").booleanValue()"; + if( Byte.TYPE == cl ) + return name + "==null?(byte)0:((Byte)" + name + ").byteValue()"; + if( Character.TYPE == cl ) + return name + "==null?(char)0:((Character)" + name + ").charValue()"; + if( Double.TYPE == cl ) + return name + "==null?(double)0:((Double)" + name + ").doubleValue()"; + if( Float.TYPE == cl ) + return name + "==null?(float)0:((Float)" + name + ").floatValue()"; + if( Integer.TYPE == cl ) + return name + "==null?(int)0:((Integer)" + name + ").intValue()"; + if( Long.TYPE == cl ) + return name + "==null?(long)0:((Long)" + name + ").longValue()"; + if( Short.TYPE == cl ) + return name + "==null?(short)0:((Short)" + name + ").shortValue()"; + throw new RuntimeException(name+" is unknown primitive type."); + } + return "(" + ReflectUtils.getName(cl) + ")"+name; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/Wrapper.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/Wrapper.java new file mode 100644 index 0000000000..ae3bfeb1f4 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/bytecode/Wrapper.java @@ -0,0 +1,410 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.bytecode; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.regex.Matcher; + +import com.alibaba.dubbo.common.utils.ClassHelper; +import com.alibaba.dubbo.common.utils.ReflectUtils; + +/** + * Wrapper. + * + * @author qian.lei + */ + +public abstract class Wrapper +{ + private static AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0); + + private static final Map, Wrapper> WRAPPER_MAP = new ConcurrentHashMap, Wrapper>(); //class wrapper map + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"}; + + private static final Wrapper OBJECT_WRAPPER = new Wrapper(){ + public String[] getMethodNames(){ return OBJECT_METHODS; } + public String[] getDeclaredMethodNames(){ return OBJECT_METHODS; } + public String[] getPropertyNames(){ return EMPTY_STRING_ARRAY; } + public Class getPropertyType(String pn){ return null; } + public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException{ throw new NoSuchPropertyException("Property [" + pn + "] not found."); } + public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException{ throw new NoSuchPropertyException("Property [" + pn + "] not found."); } + public boolean hasProperty(String name){ return false; } + public Object invokeMethod(Object instance, String mn, Class[] types, Object[] args) throws NoSuchMethodException + { + if( "getClass".equals(mn) ) return instance.getClass(); + if( "hashCode".equals(mn) ) return instance.hashCode(); + if( "toString".equals(mn) ) return instance.toString(); + if( "equals".equals(mn) ) + { + if( args.length == 1 ) return instance.equals(args[0]); + throw new IllegalArgumentException("Invoke method [" + mn + "] argument number error."); + } + throw new NoSuchMethodException("Method [" + mn + "] not found."); + } + }; + + /** + * get wrapper. + * + * @param c Class instance. + * @return Wrapper instance(not null). + */ + public static Wrapper getWrapper(Class c) + { + while( ClassGenerator.isDynamicClass(c) ) // can not wrapper on dynamic class. + c = c.getSuperclass(); + + if( c == Object.class ) + return OBJECT_WRAPPER; + + Wrapper ret = WRAPPER_MAP.get(c); + if( ret == null ) + { + ret = makeWrapper(c); + WRAPPER_MAP.put(c,ret); + } + return ret; + } + /** + * get property name array. + * + * @return property name array. + */ + abstract public String[] getPropertyNames(); + + /** + * get property type. + * + * @param pn property name. + * @return Property type or nul. + */ + abstract public Class getPropertyType(String pn); + + /** + * has property. + * + * @param name property name. + * @return has or has not. + */ + abstract public boolean hasProperty(String name); + + /** + * get property value. + * + * @param instance instance. + * @param pn property name. + * @return value. + */ + abstract public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException, IllegalArgumentException; + + /** + * set property value. + * + * @param instance instance. + * @param pn property name. + * @param pv property value. + */ + abstract public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException, IllegalArgumentException; + + /** + * get property value. + * + * @param instance instance. + * @param pns property name array. + * @return value array. + */ + public Object[] getPropertyValues(Object instance, String[] pns) throws NoSuchPropertyException, IllegalArgumentException + { + Object[] ret = new Object[pns.length]; + for(int i=0;i[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException; + + private static Wrapper makeWrapper(Class c) + { + if( c.isPrimitive() ) + throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c); + + String name = c.getName(); + ClassLoader cl = ClassHelper.getClassLoader(c); + + StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ "); + StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ "); + StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ "); + + c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); + c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); + c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); } try{"); + + Map> pts = new HashMap>(); // + Map ms = new LinkedHashMap(); // + List mns = new ArrayList(); // method names. + List dmns = new ArrayList(); // declaring method names. + + // get all public field. + for( Field f : c.getFields() ) + { + String fn = f.getName(); + Class ft = f.getType(); + if( Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()) ) + continue; + + c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }"); + c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }"); + pts.put(fn, ft); + } + + Method[] methods = c.getMethods(); + // get all public method. + for( Method m : methods ) + { + if( m.getDeclaringClass() == Object.class ) //ignore Object's method. + continue; + + String mn = m.getName(); + c3.append(" if( \"").append(mn).append("\".equals( $2 ) "); + + boolean override = false; + for( Method m2 : methods ) { + if (m != m2 && m.getName().equals(m2.getName())) { + override = true; + break; + } + } + if (override) { + int len = m.getParameterTypes().length; + c3.append(" && ").append(" $3.length == ").append(len); + if (len > 0) { + for (int l = 0; l < len; l ++) { + c3.append(" && ").append(" $3[").append(l).append("]").append(" == ") + .append(m.getParameterTypes()[l].getCanonicalName()).append(".class"); + } + } + } + + c3.append(" ) { "); + + if( m.getReturnType() == Void.TYPE ) + c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;"); + else + c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");"); + + c3.append(" }"); + + mns.add(mn); + if( m.getDeclaringClass() == c ) + dmns.add(mn); + ms.put(ReflectUtils.getDesc(m), m); + } + c3.append(" } catch(Throwable e) { " ); + c3.append(" throw new java.lang.reflect.InvocationTargetException(e); " ); + c3.append(" }"); + c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }"); + + // deal with get/set method. + Matcher matcher; + for( Map.Entry entry : ms.entrySet() ) + { + String md = entry.getKey(); + Method method = (Method)entry.getValue(); + if( ( matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() ) + { + String pn = propertyName(matcher.group(1)); + c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }"); + pts.put(pn, method.getReturnType()); + } + else if( ( matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md) ).matches() ) + { + String pn = propertyName(matcher.group(1)); + c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }"); + pts.put(pn, method.getReturnType()); + } + else if( ( matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() ) + { + Class pt = method.getParameterTypes()[0]; + String pn = propertyName(matcher.group(1)); + c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt,"$3")).append("); return; }"); + pts.put(pn, pt); + } + } + c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }"); + c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }"); + + // make class + long id = WRAPPER_CLASS_COUNTER.getAndIncrement(); + ClassGenerator cc = ClassGenerator.newInstance(cl); + cc.setClassName( ( Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw" ) + id ); + cc.setSuperClass(Wrapper.class); + + cc.addDefaultConstructor(); + cc.addField("public static String[] pns;"); // property name array. + cc.addField("public static " + Map.class.getName() + " pts;"); // property type map. + cc.addField("public static String[] mns;"); // all method name array. + cc.addField("public static String[] dmns;"); // declared method name array. + for(int i=0,len=ms.size();i wc = cc.toClass(); + // setup static field. + wc.getField("pts").set(null, pts); + wc.getField("pns").set(null, pts.keySet().toArray(new String[0])); + wc.getField("mns").set(null, mns.toArray(new String[0])); + wc.getField("dmns").set(null, dmns.toArray(new String[0])); + int ix = 0; + for( Method m : ms.values() ) + wc.getField("mts" + ix++).set(null, m.getParameterTypes()); + return (Wrapper)wc.newInstance(); + } + catch(RuntimeException e) + { + throw e; + } + catch(Throwable e) + { + throw new RuntimeException(e.getMessage(), e); + } + finally + { + cc.release(); + ms.clear(); + mns.clear(); + dmns.clear(); + } + } + + private static String arg(Class cl, String name) + { + if( cl.isPrimitive() ) + { + if( cl == Boolean.TYPE ) + return "((Boolean)" + name + ").booleanValue()"; + if( cl == Byte.TYPE ) + return "((Byte)" + name + ").byteValue()"; + if( cl == Character.TYPE ) + return "((Character)" + name + ").charValue()"; + if( cl == Double.TYPE ) + return "((Number)" + name + ").doubleValue()"; + if( cl == Float.TYPE ) + return "((Number)" + name + ").floatValue()"; + if( cl == Integer.TYPE ) + return "((Number)" + name + ").intValue()"; + if( cl == Long.TYPE ) + return "((Number)" + name + ").longValue()"; + if( cl == Short.TYPE ) + return "((Number)" + name + ").shortValue()"; + throw new RuntimeException("Unknown primitive type: " + cl.getName()); + } + return "(" + ReflectUtils.getName(cl) + ")" + name; + } + + private static String args(Class[] cs,String name) + { + int len = cs.length; + if( len == 0 ) return ""; + StringBuilder sb = new StringBuilder(); + for(int i=0;i 0 ) + sb.append(','); + sb.append(arg(cs[i],name+"["+i+"]")); + } + return sb.toString(); + } + + private static String propertyName(String pn) + { + return pn.length() == 1 || Character.isLowerCase(pn.charAt(1)) ? Character.toLowerCase(pn.charAt(0)) + pn.substring(1) : pn; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/Bytes.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/Bytes.java new file mode 100644 index 0000000000..c774da937d --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/Bytes.java @@ -0,0 +1,970 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +import com.alibaba.dubbo.common.utils.IOUtils; + +/** + * CodecUtils. + * + * @author qian.lei + */ + +public class Bytes +{ + private static final String C64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; //default base64. + + private static final char[] BASE16 = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}, BASE64 = C64.toCharArray(); + + private static final int MASK4 = 0x0f, MASK6 = 0x3f, MASK8 = 0xff; + + private static final Map DECODE_TABLE_MAP = new ConcurrentHashMap(); + + private static ThreadLocal MD = new ThreadLocal(); + + /** + * byte array copy. + * + * @param src src. + * @param length new length. + * @return new byte array. + */ + public static byte[] copyOf(byte[] src, int length) + { + byte[] dest = new byte[length]; + System.arraycopy(src, 0, dest, 0, Math.min(src.length, length)); + return dest; + } + + /** + * to byte array. + * + * @param v value. + * @return byte[]. + */ + public static byte[] short2bytes(short v) + { + byte[] ret = { 0, 0 }; + short2bytes(v, ret); + return ret; + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + */ + public static void short2bytes(short v, byte[] b) + { + short2bytes(v, b, 0); + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + */ + public static void short2bytes(short v, byte[] b, int off) + { + b[off + 1] = (byte) v; + b[off + 0] = (byte) (v >>> 8); + } + + /** + * to byte array. + * + * @param v value. + * @return byte[]. + */ + public static byte[] int2bytes(int v) + { + byte[] ret = { 0, 0, 0, 0 }; + int2bytes(v, ret); + return ret; + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + */ + public static void int2bytes(int v, byte[] b) + { + int2bytes(v, b, 0); + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + * @param off array offset. + */ + public static void int2bytes(int v, byte[] b, int off) + { + b[off + 3] = (byte) v; + b[off + 2] = (byte) (v >>> 8); + b[off + 1] = (byte) (v >>> 16); + b[off + 0] = (byte) (v >>> 24); + } + + /** + * to byte array. + * + * @param v value. + * @return byte[]. + */ + public static byte[] float2bytes(float v) + { + byte[] ret = { 0, 0, 0, 0 }; + float2bytes(v, ret); + return ret; + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + */ + public static void float2bytes(float v, byte[] b) + { + float2bytes(v, b, 0); + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + * @param off array offset. + */ + public static void float2bytes(float v, byte[] b, int off) + { + int i = Float.floatToIntBits(v); + b[off + 3] = (byte) i; + b[off + 2] = (byte) (i >>> 8); + b[off + 1] = (byte) (i >>> 16); + b[off + 0] = (byte) (i >>> 24); + } + + /** + * to byte array. + * + * @param v value. + * @return byte[]. + */ + public static byte[] long2bytes(long v) + { + byte[] ret = { 0, 0, 0, 0, 0, 0, 0, 0 }; + long2bytes(v, ret); + return ret; + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + */ + public static void long2bytes(long v, byte[] b) + { + long2bytes(v, b, 0); + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + * @param off array offset. + */ + public static void long2bytes(long v, byte[] b, int off) + { + b[off + 7] = (byte) v; + b[off + 6] = (byte) (v >>> 8); + b[off + 5] = (byte) (v >>> 16); + b[off + 4] = (byte) (v >>> 24); + b[off + 3] = (byte) (v >>> 32); + b[off + 2] = (byte) (v >>> 40); + b[off + 1] = (byte) (v >>> 48); + b[off + 0] = (byte) (v >>> 56); + } + + /** + * to byte array. + * + * @param v value. + * @return byte[]. + */ + public static byte[] double2bytes(double v) + { + byte[] ret = { 0, 0, 0, 0, 0, 0, 0, 0 }; + double2bytes(v, ret); + return ret; + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + */ + public static void double2bytes(double v, byte[] b) + { + double2bytes(v, b, 0); + } + + /** + * to byte array. + * + * @param v value. + * @param b byte array. + * @param off array offset. + */ + public static void double2bytes(double v, byte[] b, int off) + { + long j = Double.doubleToLongBits(v); + b[off + 7] = (byte) j; + b[off + 6] = (byte) (j >>> 8); + b[off + 5] = (byte) (j >>> 16); + b[off + 4] = (byte) (j >>> 24); + b[off + 3] = (byte) (j >>> 32); + b[off + 2] = (byte) (j >>> 40); + b[off + 1] = (byte) (j >>> 48); + b[off + 0] = (byte) (j >>> 56); + } + + /** + * to short. + * + * @param b byte array. + * @return short. + */ + public static short bytes2short(byte[] b) + { + return bytes2short(b, 0); + } + + /** + * to short. + * + * @param b byte array. + * @param off offset. + * @return short. + */ + public static short bytes2short(byte[] b, int off) + { + return (short) (((b[off + 1] & 0xFF) << 0) + + ((b[off + 0]) << 8)); + } + + /** + * to int. + * + * @param b byte array. + * @return int. + */ + public static int bytes2int(byte[] b) + { + return bytes2int(b, 0); + } + + /** + * to int. + * + * @param b byte array. + * @param off offset. + * @return int. + */ + public static int bytes2int(byte[] b, int off) + { + return ((b[off + 3] & 0xFF) << 0) + + ((b[off + 2] & 0xFF) << 8) + + ((b[off + 1] & 0xFF) << 16) + + ((b[off + 0]) << 24); + } + + /** + * to int. + * + * @param b byte array. + * @return int. + */ + public static float bytes2float(byte[] b) + { + return bytes2float(b, 0); + } + + /** + * to int. + * + * @param b byte array. + * @param off offset. + * @return int. + */ + public static float bytes2float(byte[] b, int off) + { + int i = ((b[off + 3] & 0xFF) << 0) + + ((b[off + 2] & 0xFF) << 8) + + ((b[off + 1] & 0xFF) << 16) + + ((b[off + 0]) << 24); + return Float.intBitsToFloat(i); + } + + /** + * to long. + * + * @param b byte array. + * @return long. + */ + public static long bytes2long(byte[] b) + { + return bytes2long(b,0); + } + + /** + * to long. + * + * @param b byte array. + * @param off offset. + * @return long. + */ + public static long bytes2long(byte[] b,int off) + { + return ((b[off + 7] & 0xFFL) << 0) + + ((b[off + 6] & 0xFFL) << 8) + + ((b[off + 5] & 0xFFL) << 16) + + ((b[off + 4] & 0xFFL) << 24) + + ((b[off + 3] & 0xFFL) << 32) + + ((b[off + 2] & 0xFFL) << 40) + + ((b[off + 1] & 0xFFL) << 48) + + (((long) b[off + 0]) << 56); + } + + /** + * to long. + * + * @param b byte array. + * @return double. + */ + public static double bytes2double(byte[] b) + { + return bytes2double(b,0); + } + + /** + * to long. + * + * @param b byte array. + * @param off offset. + * @return double. + */ + public static double bytes2double(byte[] b, int off) + { + long j = ((b[off + 7] & 0xFFL) << 0) + + ((b[off + 6] & 0xFFL) << 8) + + ((b[off + 5] & 0xFFL) << 16) + + ((b[off + 4] & 0xFFL) << 24) + + ((b[off + 3] & 0xFFL) << 32) + + ((b[off + 2] & 0xFFL) << 40) + + ((b[off + 1] & 0xFFL) << 48) + + (((long) b[off + 0]) << 56); + return Double.longBitsToDouble(j); + } + + /** + * to hex string. + * + * @param bs byte array. + * @return hex string. + */ + public static String bytes2hex(byte[] bs) + { + return bytes2hex(bs, 0, bs.length); + } + + /** + * to hex string. + * + * @param bs byte array. + * @param off offset. + * @param len length. + * @return hex string. + */ + public static String bytes2hex(byte[] bs, int off, int len) + { + if( off < 0 ) + throw new IndexOutOfBoundsException("bytes2hex: offset < 0, offset is " + off ); + if( len < 0 ) + throw new IndexOutOfBoundsException("bytes2hex: length < 0, length is " + len ); + if( off + len > bs.length ) + throw new IndexOutOfBoundsException("bytes2hex: offset + length > array length."); + + byte b; + int r = off, w = 0; + char[] cs = new char[len*2]; + for(int i=0;i> 4 & MASK4 ]; + cs[w++] = BASE16[ b & MASK4 ]; + } + return new String(cs); + } + + /** + * from hex string. + * + * @param str hex string. + * @return byte array. + */ + public static byte[] hex2bytes(String str) + { + return hex2bytes(str, 0, str.length()); + } + + /** + * from hex string. + * + * @param str hex string. + * @param off offset. + * @param len length. + * @return byte array. + */ + public static byte[] hex2bytes(final String str, final int off, int len) + { + if( ( len & 1 ) == 1 ) + throw new IllegalArgumentException("hex2bytes: ( len & 1 ) == 1."); + + if( off < 0 ) + throw new IndexOutOfBoundsException("hex2bytes: offset < 0, offset is " + off ); + if( len < 0 ) + throw new IndexOutOfBoundsException("hex2bytes: length < 0, length is " + len ); + if( off + len > str.length() ) + throw new IndexOutOfBoundsException("hex2bytes: offset + length > array length."); + + int num = len / 2, r = off, w = 0; + byte[] b = new byte[num]; + for(int i=0;i bs.length ) + throw new IndexOutOfBoundsException("bytes2base64: offset + length > array length."); + + if( code.length < 64 ) + throw new IllegalArgumentException("Base64 code length < 64."); + + boolean pad = code.length > 64; // has pad char. + int num = len / 3, rem = len % 3, r = off, w = 0; + char[] cs = new char[ num * 4 + ( rem == 0 ? 0 : pad ? 4 : rem + 1 ) ]; + + for(int i=0;i> 2 ]; + cs[w++] = code[ ( b1 << 4 ) & MASK6 | ( b2 >> 4 ) ]; + cs[w++] = code[ ( b2 << 2 ) & MASK6 | ( b3 >> 6 ) ]; + cs[w++] = code[ b3 & MASK6 ]; + } + + if( rem == 1 ) + { + int b1 = bs[r++] & MASK8; + cs[w++] = code[ b1 >> 2 ]; + cs[w++] = code[ ( b1 << 4 ) & MASK6 ]; + if( pad ) + { + cs[w++] = code[64]; + cs[w++] = code[64]; + } + } + else if( rem == 2 ) + { + int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8; + cs[w++] = code[ b1 >> 2 ]; + cs[w++] = code[ ( b1 << 4 ) & MASK6 | ( b2 >> 4 ) ]; + cs[w++] = code[ ( b2 << 2 ) & MASK6 ]; + if( pad ) + cs[w++] = code[64]; + } + return new String(cs); + } + + /** + * from base64 string. + * + * @param str base64 string. + * @return byte array. + */ + public static byte[] base642bytes(String str) + { + return base642bytes(str, 0, str.length()); + } + + /** + * from base64 string. + * + * @param str base64 string. + * @param offset offset. + * @param length length. + * @return byte array. + */ + public static byte[] base642bytes(String str, int offset, int length) + { + return base642bytes(str, offset, length, C64); + } + + /** + * from base64 string. + * + * @param str base64 string. + * @param code base64 code(0-63 is base64 char,64 is pad char). + * @return byte array. + */ + public static byte[] base642bytes(String str, String code) + { + return base642bytes(str, 0, str.length(), code); + } + + /** + * from base64 string. + * + * @param str base64 string. + * @param off offset. + * @param len length. + * @param code base64 code(0-63 is base64 char,64 is pad char). + * @return byte array. + */ + public static byte[] base642bytes(final String str, final int off, final int len, final String code) + { + if( off < 0 ) + throw new IndexOutOfBoundsException("base642bytes: offset < 0, offset is " + off ); + if( len < 0 ) + throw new IndexOutOfBoundsException("base642bytes: length < 0, length is " + len ); + if( off + len > str.length() ) + throw new IndexOutOfBoundsException("base642bytes: offset + length > string length."); + + if( code.length() < 64 ) + throw new IllegalArgumentException("Base64 code length < 64."); + + int rem = len % 4; + if( rem == 1 ) + throw new IllegalArgumentException("base642bytes: base64 string length % 4 == 1."); + + int num = len / 4, size = num * 3; + if( code.length() > 64 ) + { + if( rem != 0 ) + throw new IllegalArgumentException("base642bytes: base64 string length error."); + + char pc = code.charAt(64); + if( str.charAt(off+len-2) == pc ) + { + size -= 2; + --num; + rem = 2; + } + else if( str.charAt(off+len-1) == pc ) + { + size--; + --num; + rem = 3; + } + } + else + { + if( rem == 2 ) + size++; + else if( rem == 3 ) + size += 2; + } + + int r = off, w = 0; + byte[] b = new byte[size], t = decodeTable(code); + for(int i=0;i> 4 ) ); + b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) ); + b[w++] = (byte)( ( c3 << 6 ) | c4 ); + } + + if( rem == 2 ) + { + int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)]; + + b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) ); + } + else if( rem == 3 ) + { + int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)], c3 = t[str.charAt(r++)]; + + b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) ); + b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) ); + } + return b; + } + + /** + * from base64 string. + * + * @param str base64 string. + * @param code base64 code(0-63 is base64 char,64 is pad char). + * @return byte array. + */ + public static byte[] base642bytes(String str, char[] code) + { + return base642bytes(str, 0, str.length(), code); + } + + /** + * from base64 string. + * + * @param str base64 string. + * @param off offset. + * @param len length. + * @param code base64 code(0-63 is base64 char,64 is pad char). + * @return byte array. + */ + public static byte[] base642bytes(final String str, final int off, final int len, final char[] code) + { + if( off < 0 ) + throw new IndexOutOfBoundsException("base642bytes: offset < 0, offset is " + off ); + if( len < 0 ) + throw new IndexOutOfBoundsException("base642bytes: length < 0, length is " + len ); + if( off + len > str.length() ) + throw new IndexOutOfBoundsException("base642bytes: offset + length > string length."); + + if( code.length < 64 ) + throw new IllegalArgumentException("Base64 code length < 64."); + + int rem = len % 4; + if( rem == 1 ) + throw new IllegalArgumentException("base642bytes: base64 string length % 4 == 1."); + + int num = len / 4, size = num * 3; + if( code.length > 64 ) + { + if( rem != 0 ) + throw new IllegalArgumentException("base642bytes: base64 string length error."); + + char pc = code[64]; + if( str.charAt(off+len-2) == pc ) + size -= 2; + else if( str.charAt(off+len-1) == pc ) + size--; + } + else + { + if( rem == 2 ) + size++; + else if( rem == 3 ) + size += 2; + } + + int r = off, w = 0; + byte[] b = new byte[size]; + for(int i=0;i> 4 ) ); + b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) ); + b[w++] = (byte)( ( c3 << 6 ) | c4 ); + } + + if( rem == 2 ) + { + int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++)); + + b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) ); + } + else if( rem == 3 ) + { + int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++)), c3 = indexOf(code, str.charAt(r++)); + + b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) ); + b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) ); + } + return b; + } + + /** + * zip. + * + * @param bytes source. + * @return compressed byte array. + * @throws IOException. + */ + public static byte[] zip(byte[] bytes) throws IOException + { + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(); + OutputStream os = new DeflaterOutputStream(bos); + try + { + os.write(bytes); + } + finally + { + os.close(); + bos.close(); + } + return bos.toByteArray(); + } + + /** + * unzip. + * + * @param bytes compressed byte array. + * @return byte uncompressed array. + * @throws IOException + */ + public static byte[] unzip(byte[] bytes) throws IOException + { + UnsafeByteArrayInputStream bis = new UnsafeByteArrayInputStream(bytes); + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(); + InputStream is = new InflaterInputStream(bis); + try + { + IOUtils.write(is, bos); + return bos.toByteArray(); + } + finally + { + is.close(); + bis.close(); + bos.close(); + } + } + + /** + * get md5. + * + * @param str input string. + * @return MD5 byte array. + */ + public static byte[] getMD5(String str) + { + return getMD5(str.getBytes()); + } + + /** + * get md5. + * + * @param source byte array source. + * @return MD5 byte array. + */ + public static byte[] getMD5(byte[] source) + { + MessageDigest md = getMessageDigest(); + return md.digest(source); + } + + /** + * get md5. + * + * @param file file source. + * @return MD5 byte array. + */ + public static byte[] getMD5(File file) throws IOException + { + InputStream is = new FileInputStream(file); + try{ return getMD5(is); } + finally{ is.close(); } + } + + /** + * get md5. + * + * @param is input stream. + * @return MD5 byte array. + */ + public static byte[] getMD5(InputStream is) throws IOException + { + return getMD5(is, 1024 * 8); + } + + private static byte hex(char c) + { + if( c <= '9' ) return (byte)( c - '0' ); + if( c >= 'a' && c <= 'f' ) return (byte)( c - 'a' + 10 ); + if( c >= 'A' && c <= 'F' ) return (byte)( c - 'A' + 10 ); + throw new IllegalArgumentException("hex string format error [" + c + "]."); + } + + private static int indexOf(char[] cs, char c) + { + for(int i=0,len=cs.length;i 0 ) + { + int read, total = 0; + do + { + if( ( read = is.read(buf, total, bs-total) ) <= 0 ) + break; + total += read; + } + while( total < bs ); + md.update(buf); + } + return md.digest(); + } + + private static MessageDigest getMessageDigest() + { + MessageDigest ret = MD.get(); + if( ret == null ) + { + try + { + ret = MessageDigest.getInstance("MD5"); + MD.set(ret); + } + catch(NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + } + return ret; + } + + private Bytes(){} +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/ClassDescriptorMapper.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/ClassDescriptorMapper.java new file mode 100644 index 0000000000..96076bb623 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/ClassDescriptorMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +public interface ClassDescriptorMapper +{ + /** + * get Class-Descriptor by index. + * + * @param index index. + * @return string. + */ + String getDescriptor(int index); + + /** + * get Class-Descriptor index + * + * @param desc Class-Descriptor + * @return index. + */ + int getDescriptorIndex(String desc); +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/StreamUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/StreamUtils.java new file mode 100644 index 0000000000..a63330cc36 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/StreamUtils.java @@ -0,0 +1,220 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Stream utils. + * + * @author qian.lei + */ + +public class StreamUtils +{ + private StreamUtils(){} + + public static InputStream limitedInputStream(final InputStream is, final int limit) throws IOException + { + return new InputStream(){ + private int mPosition = 0, mMark = 0, mLimit = Math.min(limit, is.available()); + + public int read() throws IOException + { + if( mPosition < mLimit ) + { + mPosition++; + return is.read(); + } + return -1; + } + + public int read(byte b[], int off, int len) throws IOException + { + if( b == null ) + throw new NullPointerException(); + + if( off < 0 || len < 0 || len > b.length - off ) + throw new IndexOutOfBoundsException(); + + if( mPosition >= mLimit ) + return -1; + + if( mPosition + len > mLimit ) + len = mLimit - mPosition; + + if( len <= 0 ) + return 0; + + is.read(b, off, len); + mPosition += len; + return len; + } + + public long skip(long len) throws IOException + { + if( mPosition + len > mLimit ) + len = mLimit - mPosition; + + if( len <= 0 ) + return 0; + + is.skip(len); + mPosition += len; + return len; + } + + public int available() + { + return mLimit - mPosition; + } + + public boolean markSupported() + { + return is.markSupported(); + } + + public void mark(int readlimit) + { + is.mark(readlimit); + mMark = mPosition; + } + + public void reset() throws IOException + { + is.reset(); + mPosition = mMark; + } + + public void close() throws IOException + {} + }; + } + + /** + * @author ding.lid + */ + public static InputStream markSupportedInputStream(final InputStream is, final int markBufferSize) { + if(is.markSupported()) { + return is; + } + + return new InputStream() { + byte[] mMarkBuffer; + + boolean mInMarked = false; + boolean mInReset = false; + private int mPosition = 0; + private int mCount = 0; + + boolean mDry = false; + + @Override + public int read() throws IOException { + if(!mInMarked) { + return is.read(); + } + else { + if(mPosition < mCount) { + byte b = mMarkBuffer[mPosition++]; + return b & 0xFF; + } + + if(!mInReset) { + if(mDry) return -1; + + if(null == mMarkBuffer) { + mMarkBuffer = new byte[markBufferSize]; + } + if(mPosition >= markBufferSize) { + throw new IOException("Mark buffer is full!"); + } + + int read = is.read(); + if(-1 == read){ + mDry = true; + return -1; + } + + mMarkBuffer[mPosition++] = (byte) read; + mCount++; + + return read; + } + else { + // mark buffer is used, exit mark status! + mInMarked = false; + mInReset = false; + mPosition = 0; + mCount = 0; + + return is.read(); + } + } + } + + /** + * NOTE: the readlimit argument for this class + * has no meaning. + */ + @Override + public synchronized void mark(int readlimit) { + mInMarked = true; + mInReset = false; + + // mark buffer is not empty + int count = mCount - mPosition; + if(count > 0) { + System.arraycopy(mMarkBuffer, mPosition, mMarkBuffer, 0, count); + mCount = count; + mPosition = 0; + } + } + + @Override + public synchronized void reset() throws IOException { + if(!mInMarked) { + throw new IOException("should mark befor reset!"); + } + + mInReset = true; + mPosition = 0; + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public int available() throws IOException { + int available = is.available(); + + if(mInMarked && mInReset) available += mCount - mPosition; + + return available; + } + }; + } + + /** + * @author ding.lid + */ + public static InputStream markSupportedInputStream(final InputStream is) { + return markSupportedInputStream(is, 1024); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeByteArrayInputStream.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeByteArrayInputStream.java new file mode 100644 index 0000000000..248b466bb6 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeByteArrayInputStream.java @@ -0,0 +1,118 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.IOException; +import java.io.InputStream; + +/** + * UnsafeByteArrayInputStrem. + * + * @author qian.lei + */ + +public class UnsafeByteArrayInputStream extends InputStream +{ + protected byte mData[]; + + protected int mPosition, mLimit, mMark = 0; + + public UnsafeByteArrayInputStream(byte buf[]) + { + this(buf, 0, buf.length); + } + + public UnsafeByteArrayInputStream(byte buf[], int offset) + { + this(buf, offset, buf.length-offset); + } + + public UnsafeByteArrayInputStream(byte buf[], int offset, int length) + { + mData = buf; + mPosition = mMark = offset; + mLimit = Math.min(offset+length, buf.length); + } + + public int read() + { + return ( mPosition < mLimit ) ? ( mData[mPosition++] & 0xff ) : -1; + } + + public int read(byte b[], int off, int len) + { + if( b == null ) + throw new NullPointerException(); + if( off < 0 || len < 0 || len > b.length - off ) + throw new IndexOutOfBoundsException(); + if( mPosition >= mLimit ) + return -1; + if( mPosition + len > mLimit ) + len = mLimit - mPosition; + if( len <= 0 ) + return 0; + System.arraycopy(mData, mPosition, b, off, len); + mPosition += len; + return len; + } + + public long skip(long len) + { + if( mPosition + len > mLimit ) + len = mLimit - mPosition; + if( len <= 0 ) + return 0; + mPosition += len; + return len; + } + + public int available() + { + return mLimit - mPosition; + } + + public boolean markSupported() + { + return true; + } + + public void mark(int readAheadLimit) + { + mMark = mPosition; + } + + public void reset() + { + mPosition = mMark; + } + + public void close() throws IOException + {} + + public int position() + { + return mPosition; + } + + public void position(int newPosition) + { + mPosition = newPosition; + } + + public int size() { + return mData == null ? 0 : mData.length; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeByteArrayOutputStream.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeByteArrayOutputStream.java new file mode 100644 index 0000000000..3243dcd245 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeByteArrayOutputStream.java @@ -0,0 +1,106 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; + +/** + * UnsafeByteArrayOutputStream. + * + * @author qian.lei + */ + +public class UnsafeByteArrayOutputStream extends OutputStream +{ + protected byte mBuffer[]; + + protected int mCount; + + public UnsafeByteArrayOutputStream() + { + this(32); + } + + public UnsafeByteArrayOutputStream(int size) + { + if( size < 0 ) + throw new IllegalArgumentException("Negative initial size: " + size); + mBuffer = new byte[size]; + } + + public void write(int b) + { + int newcount = mCount + 1; + if( newcount > mBuffer.length ) + mBuffer = Bytes.copyOf(mBuffer, Math.max(mBuffer.length << 1, newcount)); + mBuffer[mCount] = (byte)b; + mCount = newcount; + } + + public void write(byte b[], int off, int len) + { + if( ( off < 0 ) || ( off > b.length ) || ( len < 0 ) || ( ( off + len ) > b.length ) || ( ( off + len ) < 0 ) ) + throw new IndexOutOfBoundsException(); + if( len == 0 ) + return; + int newcount = mCount + len; + if( newcount > mBuffer.length ) + mBuffer = Bytes.copyOf(mBuffer, Math.max(mBuffer.length << 1, newcount)); + System.arraycopy(b, off, mBuffer, mCount, len); + mCount = newcount; + } + + public int size() + { + return mCount; + } + + public void reset() + { + mCount = 0; + } + + public byte[] toByteArray() + { + return Bytes.copyOf(mBuffer, mCount); + } + + public ByteBuffer toByteBuffer() + { + return ByteBuffer.wrap(mBuffer, 0, mCount); + } + + public void writeTo(OutputStream out) throws IOException + { + out.write(mBuffer, 0, mCount); + } + + public String toString() + { + return new String(mBuffer, 0, mCount); + } + + public String toString(String charset) throws UnsupportedEncodingException + { + return new String(mBuffer, 0, mCount, charset); + } + + public void close() throws IOException + {} +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeStringReader.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeStringReader.java new file mode 100644 index 0000000000..3db1b5ab0a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeStringReader.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.IOException; +import java.io.Reader; + +/** + * Thread unsafed StringReader. + * + * @author qian.lei + */ + +public class UnsafeStringReader extends Reader +{ + private String mString; + + private int mPosition, mLimit, mMark; + + public UnsafeStringReader(String str) + { + mString = str; + mLimit = str.length(); + mPosition = mMark = 0; + } + + @Override + public int read() throws IOException + { + ensureOpen(); + if( mPosition >= mLimit ) + return -1; + + return mString.charAt(mPosition++); + } + + @Override + public int read(char[] cs, int off, int len) throws IOException + { + ensureOpen(); + if( (off < 0) || (off > cs.length) || (len < 0) || + ((off + len) > cs.length) || ((off + len) < 0) ) + throw new IndexOutOfBoundsException(); + + if( len == 0 ) + return 0; + + if( mPosition >= mLimit ) + return -1; + + int n = Math.min(mLimit - mPosition, len); + mString.getChars(mPosition, mPosition + n, cs, off); + mPosition += n; + return n; + } + + public long skip(long ns) throws IOException + { + ensureOpen(); + if( mPosition >= mLimit ) + return 0; + + long n = Math.min(mLimit - mPosition, ns); + n = Math.max(-mPosition, n); + mPosition += n; + return n; + } + + public boolean ready() throws IOException + { + ensureOpen(); + return true; + } + + @Override + public boolean markSupported() + { + return true; + } + + public void mark(int readAheadLimit) throws IOException + { + if( readAheadLimit < 0 ) + throw new IllegalArgumentException("Read-ahead limit < 0"); + + ensureOpen(); + mMark = mPosition; + } + + public void reset() throws IOException + { + ensureOpen(); + mPosition = mMark; + } + + @Override + public void close() throws IOException + { + mString = null; + } + + private void ensureOpen() throws IOException + { + if( mString == null ) + throw new IOException("Stream closed"); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeStringWriter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeStringWriter.java new file mode 100644 index 0000000000..7761fe18e6 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/io/UnsafeStringWriter.java @@ -0,0 +1,115 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.IOException; +import java.io.Writer; + +/** + * Thread unsafed StringWriter. + * + * @author qian.lei + */ + +public class UnsafeStringWriter extends Writer +{ + private StringBuilder mBuffer; + + public UnsafeStringWriter() + { + lock = mBuffer = new StringBuilder(); + } + + public UnsafeStringWriter(int size) + { + if( size < 0 ) + throw new IllegalArgumentException("Negative buffer size"); + + lock = mBuffer = new StringBuilder(); + } + + @Override + public void write(int c) + { + mBuffer.append((char)c); + } + + @Override + public void write(char[] cs) throws IOException + { + mBuffer.append(cs, 0, cs.length); + } + + @Override + public void write(char[] cs, int off, int len) throws IOException + { + if( (off < 0) || (off > cs.length) || (len < 0) || + ((off + len) > cs.length) || ((off + len) < 0) ) + throw new IndexOutOfBoundsException(); + + if( len > 0 ) + mBuffer.append(cs, off, len); + } + + @Override + public void write(String str) + { + mBuffer.append(str); + } + + @Override + public void write(String str, int off, int len) + { + mBuffer.append(str.substring(off, off + len)); + } + + @Override + public Writer append(CharSequence csq) + { + if (csq == null) + write("null"); + else + write(csq.toString()); + return this; + } + + @Override + public Writer append(CharSequence csq, int start, int end) + { + CharSequence cs = (csq == null ? "null" : csq); + write(cs.subSequence(start, end).toString()); + return this; + } + + @Override + public Writer append(char c) + { + mBuffer.append(c); + return this; + } + + @Override + public void close(){} + + @Override + public void flush(){} + + @Override + public String toString() + { + return mBuffer.toString(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java new file mode 100644 index 0000000000..32149c97a0 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/GenericJSONConverter.java @@ -0,0 +1,470 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.io.Bytes; + +public class GenericJSONConverter implements JSONConverter +{ + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + protected interface Encoder{ void encode(Object obj, JSONWriter jb) throws IOException; } + + protected interface Decoder{ Object decode(Object jv) throws IOException; } + + private static final Map, Encoder> GlobalEncoderMap = new HashMap, Encoder>(); + + private static final Map, Decoder> GlobalDecoderMap = new HashMap, Decoder>(); + + @SuppressWarnings("unchecked") + public void writeValue(Object obj, JSONWriter jb, boolean writeClass) throws IOException + { + if (obj == null) { + jb.valueNull(); + return; + } + Class c = obj.getClass(); + Encoder encoder = GlobalEncoderMap.get(c); + + if( encoder != null ) + { + encoder.encode(obj, jb); + } + else if( obj instanceof JSONNode ) + { + ((JSONNode)obj).writeJSON(this, jb, writeClass); + } + else if( c.isEnum() ) + { + jb.valueString(((Enum)obj).name()); + } + else if( c.isArray() ) + { + int len = Array.getLength(obj); + jb.arrayBegin(); + for(int i=0;i entry : ((Map)obj).entrySet() ) + { + key = entry.getKey(); + if( key == null ) + continue; + jb.objectItem(key.toString()); + + value = entry.getValue(); + if( value == null ) + jb.valueNull(); + else + writeValue(value, jb, writeClass); + } + jb.objectEnd(); + } + else if( Collection.class.isAssignableFrom(c) ) + { + jb.arrayBegin(); + for( Object item : (Collection)obj ) + { + if( item == null ) + jb.valueNull(); + else + writeValue(item, jb, writeClass); + } + jb.arrayEnd(); + } + else + { + jb.objectBegin(); + + Wrapper w = Wrapper.getWrapper(c); + String pns[] = w.getPropertyNames(); + + for( String pn : pns ) + { + if ((obj instanceof Throwable) && ( + "localizedMessage".equals(pn) + || "cause".equals(pn) + || "stackTrace".equals(pn))) { + continue; + } + + jb.objectItem(pn); + + Object value = w.getPropertyValue(obj,pn); + if( value == null || value == obj) + jb.valueNull(); + else + writeValue(value, jb, writeClass); + } + if (writeClass) { + jb.objectItem(JSONVisitor.CLASS_PROPERTY); + writeValue(obj.getClass().getName(), jb, writeClass); + } + jb.objectEnd(); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Object readValue(Class c, Object jv) throws IOException + { + if (jv == null) { + return null; + } + Decoder decoder = GlobalDecoderMap.get(c); + if( decoder != null ) { + return decoder.decode(jv); + } + if (c.isEnum()) { + return Enum.valueOf((Class)c, String.valueOf(jv)); + } + return jv; + } + + static + { + // init encoder map. + Encoder e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueBoolean((Boolean)obj); + } + }; + GlobalEncoderMap.put(boolean.class, e); + GlobalEncoderMap.put(Boolean.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueInt(((Number)obj).intValue()); + } + }; + GlobalEncoderMap.put(int.class, e); + GlobalEncoderMap.put(Integer.class, e); + GlobalEncoderMap.put(short.class, e); + GlobalEncoderMap.put(Short.class, e); + GlobalEncoderMap.put(byte.class, e); + GlobalEncoderMap.put(Byte.class, e); + GlobalEncoderMap.put(AtomicInteger.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueString(Character.toString((Character)obj)); + } + }; + GlobalEncoderMap.put(char.class, e); + GlobalEncoderMap.put(Character.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueLong(((Number)obj).longValue()); + } + }; + GlobalEncoderMap.put(long.class, e); + GlobalEncoderMap.put(Long.class, e); + GlobalEncoderMap.put(AtomicLong.class, e); + GlobalEncoderMap.put(BigInteger.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueFloat(((Number)obj).floatValue()); + } + }; + GlobalEncoderMap.put(float.class, e); + GlobalEncoderMap.put(Float.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueDouble(((Number)obj).doubleValue()); + } + }; + GlobalEncoderMap.put(double.class, e); + GlobalEncoderMap.put(Double.class, e); + GlobalEncoderMap.put(BigDecimal.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueString(obj.toString()); + } + }; + GlobalEncoderMap.put(String.class, e); + GlobalEncoderMap.put(StringBuilder.class, e); + GlobalEncoderMap.put(StringBuffer.class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueString(Bytes.bytes2base64((byte[])obj)); + } + }; + GlobalEncoderMap.put(byte[].class, e); + + e = new Encoder(){ + public void encode(Object obj, JSONWriter jb) throws IOException + { + jb.valueString(new SimpleDateFormat(DATE_FORMAT).format((Date)obj)); + } + }; + GlobalEncoderMap.put(Date.class, e); + + // init decoder map. + Decoder d = new Decoder(){ + public Object decode(Object jv){ + return jv.toString(); + } + }; + GlobalDecoderMap.put(String.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Boolean ) return ((Boolean)jv).booleanValue(); + return false; + } + }; + GlobalDecoderMap.put(boolean.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Boolean ) return (Boolean)jv; + return (Boolean)null; + } + }; + GlobalDecoderMap.put(Boolean.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof String && ((String)jv).length() > 0) return ((String)jv).charAt(0); + return (char)0; + } + }; + GlobalDecoderMap.put(char.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof String && ((String)jv).length() > 0) return ((String)jv).charAt(0); + return (Character)null; + } + }; + GlobalDecoderMap.put(Character.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return ((Number)jv).intValue(); + return 0; + } + }; + GlobalDecoderMap.put(int.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return Integer.valueOf(((Number)jv).intValue()); + return (Integer)null; + } + }; + GlobalDecoderMap.put(Integer.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return ((Number)jv).shortValue(); + return (short)0; + } + }; + GlobalDecoderMap.put(short.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return Short.valueOf(((Number)jv).shortValue()); + return (Short)null; + } + }; + GlobalDecoderMap.put(Short.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return ((Number)jv).longValue(); + return (long)0; + } + }; + GlobalDecoderMap.put(long.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return Long.valueOf(((Number)jv).longValue()); + return (Long)null; + } + }; + GlobalDecoderMap.put(Long.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return ((Number)jv).floatValue(); + return (float)0; + } + }; + GlobalDecoderMap.put(float.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return new Float(((Number)jv).floatValue()); + return (Float)null; + } + }; + GlobalDecoderMap.put(Float.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return ((Number)jv).doubleValue(); + return (double)0; + } + }; + GlobalDecoderMap.put(double.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return new Double(((Number)jv).doubleValue()); + return (Double)null; + } + }; + GlobalDecoderMap.put(Double.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return ((Number)jv).byteValue(); + return (byte)0; + } + }; + GlobalDecoderMap.put(byte.class, d); + + d = new Decoder(){ + public Object decode(Object jv) + { + if( jv instanceof Number ) return Byte.valueOf(((Number)jv).byteValue()); + return (Byte)null; + } + }; + GlobalDecoderMap.put(Byte.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException + { + if( jv instanceof String ) return Bytes.base642bytes((String)jv); + return (byte[])null; + } + }; + GlobalDecoderMap.put(byte[].class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException{ return new StringBuilder(jv.toString()); } + }; + GlobalDecoderMap.put(StringBuilder.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException{ return new StringBuffer(jv.toString()); } + }; + GlobalDecoderMap.put(StringBuffer.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException + { + if( jv instanceof Number ) return BigInteger.valueOf(((Number)jv).longValue()); + return (BigInteger)null; + } + }; + GlobalDecoderMap.put(BigInteger.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException + { + if( jv instanceof Number ) return BigDecimal.valueOf(((Number)jv).doubleValue()); + return (BigDecimal)null; + } + }; + GlobalDecoderMap.put(BigDecimal.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException + { + if( jv instanceof Number ) return new AtomicInteger(((Number)jv).intValue()); + return (AtomicInteger)null; + } + }; + GlobalDecoderMap.put(AtomicInteger.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException + { + if( jv instanceof Number ) return new AtomicLong(((Number)jv).longValue()); + return (AtomicLong)null; + } + }; + GlobalDecoderMap.put(AtomicLong.class, d); + + d = new Decoder(){ + public Object decode(Object jv) throws IOException + { + if( jv instanceof String ) { + try { + return new SimpleDateFormat(DATE_FORMAT).parse((String) jv); + } catch (ParseException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + if( jv instanceof Number ) + return new Date(((Number)jv).longValue()); + return (Date)null; + } + }; + GlobalDecoderMap.put(Date.class, d); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java new file mode 100644 index 0000000000..132d5eff2f --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/J2oVisitor.java @@ -0,0 +1,408 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.utils.Stack; +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * JSON to Object visitor. + * + * @author qian.lei. + */ + +class J2oVisitor implements JSONVisitor +{ + public static final boolean[] EMPTY_BOOL_ARRAY = new boolean[0]; + + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + + public static final char[] EMPTY_CHAR_ARRAY = new char[0]; + + public static final short[] EMPTY_SHORT_ARRAY = new short[0]; + + public static final int[] EMPTY_INT_ARRAY = new int[0]; + + public static final long[] EMPTY_LONG_ARRAY = new long[0]; + + public static final float[] EMPTY_FLOAT_ARRAY = new float[0]; + + public static final double[] EMPTY_DOUBLE_ARRAY = new double[0]; + + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + + private Class[] mTypes; + + private Class mType = Object[].class; + + private Object mValue; + + private Wrapper mWrapper; + + private JSONConverter mConverter; + + private Stack mStack = new Stack(); + + J2oVisitor(Class type, JSONConverter jc) + { + mType = type; + mConverter = jc; + } + + J2oVisitor(Class[] types, JSONConverter jc) + { + mTypes = types; + mConverter = jc; + } + + public void begin() + {} + + public Object end(Object obj, boolean isValue) throws ParseException + { + mStack.clear(); + try { + return mConverter.readValue(mType, obj); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + public void objectBegin() throws ParseException + { + mStack.push(mValue); + mStack.push(mType); + mStack.push(mWrapper); + + if( mType == Object.class || Map.class.isAssignableFrom(mType) ) + { + if (! mType.isInterface() && mType != Object.class) { + try { + mValue = mType.newInstance(); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } else if (mType == ConcurrentMap.class) { + mValue = new ConcurrentHashMap(); + } else { + mValue = new HashMap(); + } + mWrapper = null; + } else { + try { + mValue = mType.newInstance(); + mWrapper = Wrapper.getWrapper(mType); + } catch(IllegalAccessException e){ + throw new ParseException(StringUtils.toString(e)); + } catch(InstantiationException e){ + throw new ParseException(StringUtils.toString(e)); + } + } + } + + public Object objectEnd(int count) + { + Object ret = mValue; + mWrapper = (Wrapper)mStack.pop(); + mType = (Class)mStack.pop(); + mValue = mStack.pop(); + return ret; + } + + public void objectItem(String name) + { + mStack.push(name); // push name. + mType = ( mWrapper == null ? Object.class : mWrapper.getPropertyType(name) ); + } + + @SuppressWarnings("unchecked") + public void objectItemValue(Object obj, boolean isValue) throws ParseException + { + String name = (String)mStack.pop(); // pop name. + if( mWrapper == null ) + { + ((Map)mValue).put(name, obj); + } + else + { + if( mType != null ) + { + if( isValue && obj != null ) + { + try + { + obj = mConverter.readValue(mType, obj); + } + catch(IOException e) + { + throw new ParseException(StringUtils.toString(e)); + } + } + if (mValue instanceof Throwable && "message".equals(name)) { + try { + Field field = Throwable.class.getDeclaredField("detailMessage"); + if (! field.isAccessible()) { + field.setAccessible(true); + } + field.set(mValue, obj); + } catch (NoSuchFieldException e) { + throw new ParseException(StringUtils.toString(e)); + } catch (IllegalAccessException e) { + throw new ParseException(StringUtils.toString(e)); + } + } else if (! CLASS_PROPERTY.equals(name)) { + mWrapper.setPropertyValue(mValue, name, obj); + } + } + } + } + + public void arrayBegin() throws ParseException + { + mStack.push(mType); + + if( mType.isArray() ) + mType = mType.getComponentType(); + else if( mType == Object.class || Collection.class.isAssignableFrom(mType) ) + mType = Object.class; + else + throw new ParseException("Convert error, can not load json array data into class [" + mType.getName() + "]."); + } + + @SuppressWarnings("unchecked") + public Object arrayEnd(int count) throws ParseException + { + Object ret; + mType = (Class)mStack.get(-1-count); + + if( mType.isArray() ) + { + ret = toArray(mType.getComponentType(), mStack, count); + } + else + { + Collection items; + if( mType == Object.class || Collection.class.isAssignableFrom(mType)) { + if (! mType.isInterface() && mType != Object.class) { + try { + items = (Collection) mType.newInstance(); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } else if (mType.isAssignableFrom(ArrayList.class)) { // List + items = new ArrayList(count); + } else if (mType.isAssignableFrom(HashSet.class)) { // Set + items = new HashSet(count); + } else if (mType.isAssignableFrom(LinkedList.class)) { // Queue + items = new LinkedList(); + } else { // Other + items = new ArrayList(count); + } + } else { + throw new ParseException("Convert error, can not load json array data into class [" + mType.getName() + "]."); + } + for(int i=0;i c, Stack list, int len) throws ParseException + { + if( c == String.class ) + { + if( len == 0 ) + { + return EMPTY_STRING_ARRAY; + } + else + { + Object o; + String ss[] = new String[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + ss[i] = ( o == null ? null : o.toString() ); + } + return ss; + } + } + if( c == boolean.class ) + { + if( len == 0 ) return EMPTY_BOOL_ARRAY; + Object o; + boolean[] ret = new boolean[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Boolean ) + ret[i] = ((Boolean)o).booleanValue(); + } + return ret; + } + if( c == int.class ) + { + if( len == 0 ) return EMPTY_INT_ARRAY; + Object o; + int[] ret = new int[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Number ) + ret[i] = ((Number)o).intValue(); + } + return ret; + } + if( c == long.class ) + { + if( len == 0 ) return EMPTY_LONG_ARRAY; + Object o; + long[] ret = new long[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Number ) + ret[i] = ((Number)o).longValue(); + } + return ret; + } + if( c == float.class ) + { + if( len == 0 ) return EMPTY_FLOAT_ARRAY; + Object o; + float[] ret = new float[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Number ) + ret[i] = ((Number)o).floatValue(); + } + return ret; + } + if( c == double.class ) + { + if( len == 0 ) return EMPTY_DOUBLE_ARRAY; + Object o; + double[] ret = new double[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Number ) + ret[i] = ((Number)o).doubleValue(); + } + return ret; + } + if( c == byte.class ) + { + if( len == 0 ) return EMPTY_BYTE_ARRAY; + Object o; + byte[] ret = new byte[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Number ) + ret[i] = ((Number)o).byteValue(); + } + return ret; + } + if( c == char.class ) + { + if( len == 0 ) return EMPTY_CHAR_ARRAY; + Object o; + char[] ret = new char[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Character ) + ret[i] = ((Character)o).charValue(); + } + return ret; + } + if( c == short.class ) + { + if( len == 0 ) return EMPTY_SHORT_ARRAY; + Object o; + short[] ret = new short[len]; + for(int i=len-1;i>=0;i--) + { + o = list.pop(); + if( o instanceof Number ) + ret[i] = ((Number)o).shortValue(); + } + return ret; + } + + Object ret = Array.newInstance(c, len); + for(int i=len-1;i>=0;i--) + Array.set(ret, i, list.pop()); + return ret; + } + + private static String name(Class[] types) + { + StringBuilder sb = new StringBuilder(); + for(int i=0;i 0 ) + sb.append(", "); + sb.append(types[i].getName()); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java new file mode 100644 index 0000000000..828d9b833a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSON.java @@ -0,0 +1,761 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; + +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.utils.Stack; + +/** + * JSON. + * + * @author qian.lei + */ + +public class JSON +{ + public static final char LBRACE = '{', RBRACE = '}'; + + public static final char LSQUARE = '[', RSQUARE = ']'; + + public static final char COMMA = ',', COLON = ':', QUOTE = '"'; + + public static final String NULL = "null"; + + static final JSONConverter DEFAULT_CONVERTER = new GenericJSONConverter(); + + // state. + public static final byte END = 0, START = 1, OBJECT_ITEM = 2, OBJECT_VALUE = 3, ARRAY_ITEM = 4; + + private static class Entry + { + byte state; + Object value; + Entry(byte s, Object v){ state = s; value = v; } + } + + private JSON(){} + + /** + * json string. + * + * @param obj object. + * @return json string. + * @throws IOException. + */ + public static String json(Object obj) throws IOException + { + if( obj == null ) return NULL; + StringWriter sw = new StringWriter(); + try + { + json(obj, sw); + return sw.getBuffer().toString(); + } + finally{ sw.close(); } + } + + /** + * write json. + * + * @param obj object. + * @param writer writer. + * @throws IOException. + */ + public static void json(Object obj, Writer writer) throws IOException + { + json(obj, writer, false); + } + + public static void json(Object obj, Writer writer, boolean writeClass) throws IOException + { + if( obj == null ) + writer.write(NULL); + else + json(obj, new JSONWriter(writer), writeClass); + } + + /** + * json string. + * + * @param obj object. + * @param properties property name array. + * @return json string. + * @throws IOException. + */ + public static String json(Object obj, String[] properties) throws IOException + { + if( obj == null ) return NULL; + StringWriter sw = new StringWriter(); + try + { + json(obj, properties, sw); + return sw.getBuffer().toString(); + } + finally{ sw.close(); } + } + + public static void json(Object obj, final String[] properties, Writer writer) throws IOException + { + json(obj, properties, writer, false); + } + + /** + * write json. + * + * @param obj object. + * @param properties property name array. + * @param writer writer. + * @throws IOException. + */ + public static void json(Object obj, final String[] properties, Writer writer, boolean writeClass) throws IOException + { + if( obj == null ) + writer.write(NULL); + else + json(obj, properties, new JSONWriter(writer), writeClass); + } + + private static void json(Object obj, JSONWriter jb, boolean writeClass) throws IOException + { + if( obj == null ) + jb.valueNull(); + else + DEFAULT_CONVERTER.writeValue(obj, jb, writeClass); + } + + private static void json(Object obj, String[] properties, JSONWriter jb, boolean writeClass) throws IOException + { + if( obj == null ) + { + jb.valueNull(); + } + else + { + Wrapper wrapper = Wrapper.getWrapper(obj.getClass()); + + Object value; + jb.objectBegin(); + for( String prop : properties ) + { + jb.objectItem(prop); + value = wrapper.getPropertyValue(obj, prop); + if( value == null ) + jb.valueNull(); + else + DEFAULT_CONVERTER.writeValue(value, jb, writeClass); + } + jb.objectEnd(); + } + } + + /** + * parse json. + * + * @param json json source. + * @return JSONObject or JSONArray or Boolean or Long or Double or String or null + * @throws ParseException + */ + public static Object parse(String json) throws ParseException + { + StringReader reader = new StringReader(json); + try{ return parse(reader); } + catch(IOException e){ throw new ParseException(e.getMessage()); } + finally{ reader.close(); } + } + + /** + * parse json. + * + * @param reader reader. + * @return JSONObject or JSONArray or Boolean or Long or Double or String or null + * @throws IOException + * @throws ParseException + */ + public static Object parse(Reader reader) throws IOException, ParseException + { + return parse(reader, JSONToken.ANY); + } + + /** + * parse json. + * + * @param json json string. + * @param type target type. + * @return result. + * @throws ParseException + */ + public static T parse(String json, Class type) throws ParseException + { + StringReader reader = new StringReader(json); + try{ return parse(reader, type); } + catch(IOException e){ throw new ParseException(e.getMessage()); } + finally{ reader.close(); } + } + + /** + * parse json + * + * @param reader json source. + * @param type target type. + * @return result. + * @throws IOException + * @throws ParseException + */ + @SuppressWarnings("unchecked") + public static T parse(Reader reader, Class type) throws IOException, ParseException + { + return (T)parse(reader, new J2oVisitor(type, DEFAULT_CONVERTER), JSONToken.ANY); + } + + /** + * parse json. + * + * @param json json string. + * @param types target type array. + * @return result. + * @throws ParseException + */ + public static Object[] parse(String json, Class[] types) throws ParseException + { + StringReader reader = new StringReader(json); + try{ return (Object[])parse(reader, types); } + catch(IOException e){ throw new ParseException(e.getMessage()); } + finally{ reader.close(); } + } + + /** + * parse json. + * + * @param reader json source. + * @param types target type array. + * @return result. + * @throws IOException + * @throws ParseException + */ + public static Object[] parse(Reader reader, Class[] types) throws IOException, ParseException + { + return (Object[])parse(reader, new J2oVisitor(types, DEFAULT_CONVERTER), JSONToken.LSQUARE); + } + + /** + * parse json. + * + * @param json json string. + * @param handler handler. + * @return result. + * @throws ParseException + */ + public static Object parse(String json, JSONVisitor handler) throws ParseException + { + StringReader reader = new StringReader(json); + try{ return parse(reader, handler); } + catch(IOException e){ throw new ParseException(e.getMessage()); } + finally{ reader.close(); } + } + + /** + * parse json. + * + * @param reader json source. + * @param handler handler. + * @return resule. + * @throws IOException + * @throws ParseException + */ + public static Object parse(Reader reader, JSONVisitor handler) throws IOException, ParseException + { + return parse(reader, handler, JSONToken.ANY); + } + + private static Object parse(Reader reader, int expect) throws IOException, ParseException + { + JSONReader jr = new JSONReader(reader); + JSONToken token = jr.nextToken(expect); + + byte state = START; + Object value = null, tmp; + Stack stack = new Stack(); + + do + { + switch( state ) + { + case END: + throw new ParseException("JSON source format error."); + case START: + { + switch( token.type ) + { + case JSONToken.NULL: case JSONToken.BOOL: case JSONToken.INT: case JSONToken.FLOAT: case JSONToken.STRING: + { + state = END; + value = token.value; + break; + } + case JSONToken.LSQUARE: + { + state = ARRAY_ITEM; + value = new JSONArray(); + break; + } + case JSONToken.LBRACE: + { + state = OBJECT_ITEM; + value = new JSONObject(); + break; + } + default: + throw new ParseException("Unexcepted token expect [ VALUE or '[' or '{' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + case ARRAY_ITEM: + { + switch( token.type ) + { + case JSONToken.COMMA: + break; + case JSONToken.NULL: case JSONToken.BOOL: case JSONToken.INT: case JSONToken.FLOAT: case JSONToken.STRING: + { + ((JSONArray)value).add(token.value); + break; + } + case JSONToken.RSQUARE: // end of array. + { + if( stack.isEmpty() ) + { + state = END; + } + else + { + Entry entry = stack.pop(); + state = entry.state; + value = entry.value; + } + break; + } + case JSONToken.LSQUARE: // array begin. + { + tmp = new JSONArray(); + ((JSONArray)value).add(tmp); + stack.push(new Entry(state, value)); + + state = ARRAY_ITEM; + value = tmp; + break; + } + case JSONToken.LBRACE: // object begin. + { + tmp = new JSONObject(); + ((JSONArray)value).add(tmp); + stack.push(new Entry(state, value)); + + state = OBJECT_ITEM; + value = tmp; + break; + } + default: + throw new ParseException("Unexcepted token expect [ VALUE or ',' or ']' or '[' or '{' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + case OBJECT_ITEM: + { + switch( token.type ) + { + case JSONToken.COMMA: + break; + case JSONToken.IDENT: // item name. + { + stack.push(new Entry(OBJECT_ITEM, (String)token.value)); + state = OBJECT_VALUE; + break; + } + case JSONToken.NULL: + { + stack.push(new Entry(OBJECT_ITEM, "null")); + state = OBJECT_VALUE; + break; + } + case JSONToken.BOOL: case JSONToken.INT: case JSONToken.FLOAT: case JSONToken.STRING: + { + stack.push(new Entry(OBJECT_ITEM, token.value.toString())); + state = OBJECT_VALUE; + break; + } + case JSONToken.RBRACE: // end of object. + { + if( stack.isEmpty() ) + { + state = END; + } + else + { + Entry entry = stack.pop(); + state = entry.state; + value = entry.value; + } + break; + } + default: + throw new ParseException("Unexcepted token expect [ IDENT or VALUE or ',' or '}' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + case OBJECT_VALUE: + { + switch( token.type ) + { + case JSONToken.COLON: + break; + case JSONToken.NULL: case JSONToken.BOOL: case JSONToken.INT: case JSONToken.FLOAT: case JSONToken.STRING: + { + ((JSONObject)value).put((String)stack.pop().value, token.value); + state = OBJECT_ITEM; + break; + } + case JSONToken.LSQUARE: // array begin. + { + tmp = new JSONArray(); + ((JSONObject)value).put((String)stack.pop().value, tmp); + stack.push(new Entry(OBJECT_ITEM, value)); + + state = ARRAY_ITEM; + value = tmp; + break; + } + case JSONToken.LBRACE: // object begin. + { + tmp = new JSONObject(); + ((JSONObject)value).put((String)stack.pop().value, tmp); + stack.push(new Entry(OBJECT_ITEM, value)); + + state = OBJECT_ITEM; + value = tmp; + break; + } + default: + throw new ParseException("Unexcepted token expect [ VALUE or '[' or '{' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + default: + throw new ParseException("Unexcepted state."); + } + } + while( ( token = jr.nextToken() ) != null ); + stack.clear(); + return value; + } + + private static Object parse(Reader reader, JSONVisitor handler, int expect) throws IOException, ParseException + { + JSONReader jr = new JSONReader(reader); + JSONToken token = jr.nextToken(expect); + + Object value = null; + int state = START, index = 0; + Stack states = new Stack(); + boolean pv = false; + + handler.begin(); + do + { + switch( state ) + { + case END: + throw new ParseException("JSON source format error."); + case START: + { + switch( token.type ) + { + case JSONToken.NULL: + { + value = token.value; + state = END; + pv = true; + break; + } + case JSONToken.BOOL: + { + value = token.value; + state = END; + pv = true; + break; + } + case JSONToken.INT: + { + value = token.value; + state = END; + pv = true; + break; + } + case JSONToken.FLOAT: + { + value = token.value; + state = END; + pv = true; + break; + } + case JSONToken.STRING: + { + value = token.value; + state = END; + pv = true; + break; + } + case JSONToken.LSQUARE: + { + handler.arrayBegin(); + state = ARRAY_ITEM; + break; + } + case JSONToken.LBRACE: + { + handler.objectBegin(); + state = OBJECT_ITEM; + break; + } + default: + throw new ParseException("Unexcepted token expect [ VALUE or '[' or '{' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + case ARRAY_ITEM: + { + switch( token.type ) + { + case JSONToken.COMMA: + break; + case JSONToken.NULL: + { + handler.arrayItem(index++); + handler.arrayItemValue(index, token.value, true); + break; + } + case JSONToken.BOOL: + { + handler.arrayItem(index++); + handler.arrayItemValue(index, token.value, true); + break; + } + case JSONToken.INT: + { + handler.arrayItem(index++); + handler.arrayItemValue(index, token.value, true); + break; + } + case JSONToken.FLOAT: + { + handler.arrayItem(index++); + handler.arrayItemValue(index, token.value, true); + break; + } + case JSONToken.STRING: + { + handler.arrayItem(index++); + handler.arrayItemValue(index, token.value, true); + break; + } + case JSONToken.LSQUARE: + { + handler.arrayItem(index++); + states.push(new int[]{state, index}); + + index = 0; + state = ARRAY_ITEM; + handler.arrayBegin(); + break; + } + case JSONToken.LBRACE: + { + handler.arrayItem(index++); + states.push(new int[]{state, index}); + + index = 0; + state = OBJECT_ITEM; + handler.objectBegin(); + break; + } + case JSONToken.RSQUARE: + { + if( states.isEmpty() ) + { + value = handler.arrayEnd(index); + state = END; + } + else + { + value = handler.arrayEnd(index); + int[] tmp = states.pop(); + state = tmp[0]; + index = tmp[1]; + + switch( state ) + { + case ARRAY_ITEM: + { + handler.arrayItemValue(index, value, false); + break; + } + case OBJECT_ITEM: + { + handler.objectItemValue(value, false); + break; + } + } + } + break; + } + default: + throw new ParseException("Unexcepted token expect [ VALUE or ',' or ']' or '[' or '{' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + case OBJECT_ITEM: + { + switch( token.type ) + { + case JSONToken.COMMA: + break; + case JSONToken.IDENT: + { + handler.objectItem((String)token.value); + state = OBJECT_VALUE; + break; + } + case JSONToken.NULL: + { + handler.objectItem("null"); + state = OBJECT_VALUE; + break; + } + case JSONToken.BOOL: case JSONToken.INT: case JSONToken.FLOAT: case JSONToken.STRING: + { + handler.objectItem(token.value.toString()); + state = OBJECT_VALUE; + break; + } + case JSONToken.RBRACE: + { + if( states.isEmpty() ) + { + value = handler.objectEnd(index); + state = END; + } + else + { + value = handler.objectEnd(index); + int[] tmp = states.pop(); + state = tmp[0]; + index = tmp[1]; + + switch( state ) + { + case ARRAY_ITEM: + { + handler.arrayItemValue(index, value, false); + break; + } + case OBJECT_ITEM: + { + handler.objectItemValue(value, false); + break; + } + } + } + break; + } + default: + throw new ParseException("Unexcepted token expect [ IDENT or VALUE or ',' or '}' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + case OBJECT_VALUE: + { + switch( token.type ) + { + case JSONToken.COLON: + break; + case JSONToken.NULL: + { + handler.objectItemValue(token.value, true); + state = OBJECT_ITEM; + break; + } + case JSONToken.BOOL: + { + handler.objectItemValue(token.value, true); + state = OBJECT_ITEM; + break; + } + case JSONToken.INT: + { + handler.objectItemValue(token.value, true); + state = OBJECT_ITEM; + break; + } + case JSONToken.FLOAT: + { + handler.objectItemValue(token.value, true); + state = OBJECT_ITEM; + break; + } + case JSONToken.STRING: + { + handler.objectItemValue(token.value, true); + state = OBJECT_ITEM; + break; + } + case JSONToken.LSQUARE: + { + states.push(new int[]{OBJECT_ITEM, index}); + + index = 0; + state = ARRAY_ITEM; + handler.arrayBegin(); + break; + } + case JSONToken.LBRACE: + { + states.push(new int[]{OBJECT_ITEM, index}); + + index = 0; + state = OBJECT_ITEM; + handler.objectBegin(); + break; + } + default: + throw new ParseException("Unexcepted token expect [ VALUE or '[' or '{' ] get '" + JSONToken.token2string(token.type) + "'"); + } + break; + } + default: + throw new ParseException("Unexcepted state."); + } + } + while( ( token = jr.nextToken() ) != null ); + states.clear(); + return handler.end(value, pv); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java new file mode 100644 index 0000000000..a0449e1cd4 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONArray.java @@ -0,0 +1,202 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * JSONArray. + * + * @author qian.lei + */ + +public class JSONArray implements JSONNode +{ + private List mArray = new ArrayList(); + + /** + * get. + * + * @param index index. + * @return boolean or long or double or String or JSONArray or JSONObject or null. + */ + public Object get(int index) + { + return mArray.get(index); + } + + /** + * get boolean value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public boolean getBoolean(int index, boolean def) + { + Object tmp = mArray.get(index); + return tmp != null && tmp instanceof Boolean ? ((Boolean)tmp).booleanValue() : def; + } + + /** + * get int value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public int getInt(int index, int def) + { + Object tmp = mArray.get(index); + return tmp != null && tmp instanceof Number ? ((Number)tmp).intValue() : def; + } + + /** + * get long value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public long getLong(int index, long def) + { + Object tmp = mArray.get(index); + return tmp != null && tmp instanceof Number ? ((Number)tmp).longValue() : def; + } + + /** + * get float value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public float getFloat(int index, float def) + { + Object tmp = mArray.get(index); + return tmp != null && tmp instanceof Number ? ((Number)tmp).floatValue() : def; + } + + /** + * get double value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public double getDouble(int index, double def) + { + Object tmp = mArray.get(index); + return tmp != null && tmp instanceof Number ? ((Number)tmp).doubleValue() : def; + } + + /** + * get string value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public String getString(int index) + { + Object tmp = mArray.get(index); + return tmp == null ? null : tmp.toString(); + } + + /** + * get JSONArray value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public JSONArray getArray(int index) + { + Object tmp = mArray.get(index); + return tmp == null ? null : tmp instanceof JSONArray ? (JSONArray)tmp : null; + } + + /** + * get JSONObject value. + * + * @param index index. + * @param def default value. + * @return value or default value. + */ + public JSONObject getObject(int index) + { + Object tmp = mArray.get(index); + return tmp == null ? null : tmp instanceof JSONObject ? (JSONObject)tmp : null; + } + + /** + * get array length. + * + * @return length. + */ + public int length() + { + return mArray.size(); + } + + /** + * add item. + */ + public void add(Object ele) + { + mArray.add(ele); + } + + /** + * add items. + */ + public void addAll(Object[] eles) + { + for( Object ele : eles ) + mArray.add(ele); + } + + /** + * add items. + */ + public void addAll(Collection c) + { + mArray.addAll(c); + } + + /** + * write json. + * + * @param jc json converter + * @param jb json builder. + * @return json string. + */ + public void writeJSON(JSONConverter jc, JSONWriter jb, boolean writeClass) throws IOException + { + jb.arrayBegin(); + for( Object item : mArray ) + { + if( item == null ) + jb.valueNull(); + else + jc.writeValue(item, jb, writeClass); + } + jb.arrayEnd(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java new file mode 100644 index 0000000000..921460abb7 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONConverter.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; + +/** + * JSON converter. + * + * @author qianlei + */ + +public interface JSONConverter +{ + /** + * write object. + * + * @param obj obj. + * @param builder builder. + * @throws IOException + */ + void writeValue(Object obj, JSONWriter builder, boolean writeClass) throws IOException; + + /** + * convert json value to target class. + * + * @param type target type. + * @param jv json value. + * @return target object. + * @throws IOException. + */ + Object readValue(Class type, Object jv) throws IOException; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java new file mode 100644 index 0000000000..131f8b0d09 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONNode.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; + +/** + * JSONSerializable. + * + * @author qian.lei + */ + +interface JSONNode +{ + /** + * write json string. + * + * @param jc json converter. + * @param jb json builder. + * @throws IOException + */ + void writeJSON(JSONConverter jc, JSONWriter jb, boolean writeClass) throws IOException; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java new file mode 100644 index 0000000000..7147d26ad0 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONObject.java @@ -0,0 +1,227 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * JSONObject. + * + * @author qian.lei + */ + +public class JSONObject implements JSONNode +{ + private Map mMap = new HashMap(); + + /** + * get. + * + * @param key key. + * @return boolean or long or double or String or JSONArray or JSONObject or null. + */ + public Object get(String key) + { + return mMap.get(key); + } + + /** + * get boolean value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public boolean getBoolean(String key, boolean def) + { + Object tmp = mMap.get(key); + return tmp != null && tmp instanceof Boolean ? (Boolean)tmp : def; + } + + /** + * get int value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public int getInt(String key, int def) + { + Object tmp = mMap.get(key); + return tmp != null && tmp instanceof Number ? ((Number)tmp).intValue() : def; + } + + /** + * get long value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public long getLong(String key, long def) + { + Object tmp = mMap.get(key); + return tmp != null && tmp instanceof Number ? ((Number)tmp).longValue() : def; + } + + /** + * get float value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public float getFloat(String key, float def) + { + Object tmp = mMap.get(key); + return tmp != null && tmp instanceof Number ? ((Number)tmp).floatValue() : def; + } + + /** + * get double value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public double getDouble(String key, double def) + { + Object tmp = mMap.get(key); + return tmp != null && tmp instanceof Number ? ((Number)tmp).doubleValue() : def; + } + + /** + * get string value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public String getString(String key) + { + Object tmp = mMap.get(key); + return tmp == null ? null : tmp.toString(); + } + + /** + * get JSONArray value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public JSONArray getArray(String key) + { + Object tmp = mMap.get(key); + return tmp == null ? null : tmp instanceof JSONArray ? (JSONArray)tmp : null; + } + + /** + * get JSONObject value. + * + * @param key key. + * @param def default value. + * @return value or default value. + */ + public JSONObject getObject(String key) + { + Object tmp = mMap.get(key); + return tmp == null ? null : tmp instanceof JSONObject ? (JSONObject)tmp : null; + } + + /** + * get key iterator. + * + * @return key iterator. + */ + public Iterator keys() + { + return mMap.keySet().iterator(); + } + + /** + * contains key. + * + * @param key key. + * @return contains or not. + */ + public boolean contains(String key) + { + return mMap.containsKey(key); + } + + /** + * put value. + * + * @param name name. + * @param value value. + */ + public void put(String name, Object value) + { + mMap.put(name, value); + } + + /** + * put all. + * + * @param names name array. + * @param values value array. + */ + public void putAll(String[] names, Object[] values) + { + for(int i=0,len=Math.min(names.length, values.length);i map) + { + for( Map.Entry entry : map.entrySet() ) + mMap.put(entry.getKey(), entry.getValue()); + } + + /** + * write json. + * + * @param jc json converter. + * @param jb json builder. + * @return json string. + */ + public void writeJSON(JSONConverter jc, JSONWriter jb, boolean writeClass) throws IOException + { + String key; + Object value; + jb.objectBegin(); + for( Map.Entry entry : mMap.entrySet() ) + { + key = entry.getKey(); + jb.objectItem(key); + value = entry.getValue(); + if( value == null ) + jb.valueNull(); + else + jc.writeValue(value, jb, writeClass); + } + jb.objectEnd(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java new file mode 100644 index 0000000000..f32a721df2 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONReader.java @@ -0,0 +1,75 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; + +/** + * JSON reader. + * + * @author qian.lei + */ + +public class JSONReader +{ + private static ThreadLocal LOCAL_LEXER = new ThreadLocal(){}; + + private Yylex mLex; + + public JSONReader(InputStream is, String charset) throws UnsupportedEncodingException + { + this(new InputStreamReader(is, charset)); + } + + public JSONReader(Reader reader) + { + mLex = getLexer(reader); + } + + public JSONToken nextToken() throws IOException, ParseException + { + return mLex.yylex(); + } + + public JSONToken nextToken(int expect) throws IOException, ParseException + { + JSONToken ret = mLex.yylex(); + if( ret == null ) + throw new ParseException("EOF error."); + if( expect != JSONToken.ANY && expect != ret.type ) + throw new ParseException("Unexcepted token."); + return ret; + } + + private static Yylex getLexer(Reader reader) + { + Yylex ret = LOCAL_LEXER.get(); + if( ret == null ) + { + ret = new Yylex(reader); + LOCAL_LEXER.set(ret); + } + else + { + ret.yyreset(reader); + } + return ret; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java new file mode 100644 index 0000000000..b3c925d5e2 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONToken.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +/** + * JSONToken. + * + * @author qian.lei + */ + +public class JSONToken +{ + // token type + public static final int ANY = 0, IDENT = 0x01, LBRACE = 0x02, LSQUARE = 0x03, RBRACE = 0x04, RSQUARE = 0x05, COMMA = 0x06, COLON = 0x07; + + public static final int NULL = 0x10, BOOL = 0x11, INT = 0x12, FLOAT = 0x13, STRING = 0x14, ARRAY = 0x15, OBJECT = 0x16; + + public final int type; + + public final Object value; + + JSONToken(int t) + { + this(t, null); + } + + JSONToken(int t, Object v) + { + type = t; + value = v; + } + + static String token2string(int t) + { + switch( t ) + { + case LBRACE: return "{"; + case RBRACE: return "}"; + case LSQUARE: return "["; + case RSQUARE: return "]"; + case COMMA: return ","; + case COLON: return ":"; + case IDENT: return "IDENT"; + case NULL: return "NULL"; + case BOOL: return "BOOL VALUE"; + case INT: return "INT VALUE"; + case FLOAT: return "FLOAT VALUE"; + case STRING: return "STRING VALUE"; + default: return "ANY"; + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java new file mode 100644 index 0000000000..d04f53107f --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONVisitor.java @@ -0,0 +1,109 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +/** + * JSONVisitor. + * + * @author qian.lei + */ + +public interface JSONVisitor +{ + public static final String CLASS_PROPERTY = "class"; + + /** + * parse begin . + */ + void begin(); + + /** + * parse end. + * + * @param obj root obj. + * @param isValue is json value. + * @return parse result. + * @throws ParseException + */ + Object end(Object obj, boolean isValue) throws ParseException; + + /** + * object begin. + * + * @throws ParseException + */ + void objectBegin() throws ParseException; + + /** + * object end, return object value. + * + * @param count property count. + * @return object value. + * @throws ParseException + */ + Object objectEnd(int count) throws ParseException; + + /** + * object property name. + * + * @param name name. + * @throws ParseException + */ + void objectItem(String name) throws ParseException; + + /** + * object property value. + * + * @param obj obj. + * @param isValue is json value. + * @throws ParseException + */ + void objectItemValue(Object obj, boolean isValue) throws ParseException; + + /** + * array begin. + * + * @throws ParseException + */ + void arrayBegin() throws ParseException; + + /** + * array end, return array value. + * + * @param count count. + * @return array value. + * @throws ParseException + */ + Object arrayEnd(int count) throws ParseException; + + /** + * array item. + * + * @param index index. + * @throws ParseException + */ + void arrayItem(int index) throws ParseException; + + /** + * array item. + * + * @param index index. + * @param obj item. + * @param isValue is json value. + * @throws ParseException + */ + void arrayItemValue(int index, Object obj, boolean isValue) throws ParseException; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java new file mode 100644 index 0000000000..9d90bf0937 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/JSONWriter.java @@ -0,0 +1,325 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import com.alibaba.dubbo.common.utils.Stack; + +/** + * JSON Writer. + * + * w.objectBegin().objectItem("name").valueString("qianlei").objectEnd() = {name:"qianlei"}. + * + * @author qian.lei + */ + +public class JSONWriter +{ + private static final byte UNKNOWN = 0, ARRAY = 1, OBJECT = 2, OBJECT_VALUE = 3; + + private static class State + { + private byte type; + private int itemCount = 0; + + State(byte t){ type = t; } + } + + private Writer mWriter; + + private State mState = new State(UNKNOWN); + + private Stack mStack = new Stack(); + + public JSONWriter(Writer writer) + { + mWriter = writer; + } + + public JSONWriter(OutputStream is, String charset) throws UnsupportedEncodingException + { + mWriter = new OutputStreamWriter(is, charset); + } + + /** + * object begin. + * + * @return this. + * @throws IOException. + */ + public JSONWriter objectBegin() throws IOException + { + beforeValue(); + + mWriter.write(JSON.LBRACE); + mStack.push(mState); + mState = new State(OBJECT); + return this; + } + + /** + * object end. + * + * @return this. + * @throws IOException. + */ + public JSONWriter objectEnd() throws IOException + { + mWriter.write(JSON.RBRACE); + mState = mStack.pop(); + return this; + } + + /** + * object item. + * + * @param name name. + * @return this. + * @throws IOException. + */ + public JSONWriter objectItem(String name) throws IOException + { + beforeObjectItem(); + + mWriter.write(JSON.QUOTE); + mWriter.write(escape(name)); + mWriter.write(JSON.QUOTE); + mWriter.write(JSON.COLON); + return this; + } + + /** + * array begin. + * + * @return this. + * @throws IOException. + */ + public JSONWriter arrayBegin() throws IOException + { + beforeValue(); + + mWriter.write(JSON.LSQUARE); + mStack.push(mState); + mState = new State(ARRAY); + return this; + } + + /** + * array end, return array value. + * + * @return this. + * @throws IOException. + */ + public JSONWriter arrayEnd() throws IOException + { + mWriter.write(JSON.RSQUARE); + mState = mStack.pop(); + return this; + } + + /** + * value. + * + * @return this. + * @throws IOException. + */ + public JSONWriter valueNull() throws IOException + { + beforeValue(); + + mWriter.write(JSON.NULL); + return this; + } + + /** + * value. + * + * @param value value. + * @return this. + * @throws IOException + */ + public JSONWriter valueString(String value) throws IOException + { + beforeValue(); + + mWriter.write(JSON.QUOTE); + mWriter.write(escape(value)); + mWriter.write(JSON.QUOTE); + return this; + } + + /** + * value. + * + * @param value value. + * @return this. + * @throws IOException + */ + public JSONWriter valueBoolean(boolean value) throws IOException + { + beforeValue(); + + mWriter.write(value ? "true" : "false"); + return this; + } + + /** + * value. + * + * @param value value. + * @return this. + * @throws IOException + */ + public JSONWriter valueInt(int value) throws IOException + { + beforeValue(); + + mWriter.write(String.valueOf(value)); + return this; + } + + /** + * value. + * + * @param value value. + * @return this. + * @throws IOException + */ + public JSONWriter valueLong(long value) throws IOException + { + beforeValue(); + + mWriter.write(String.valueOf(value)); + return this; + } + + /** + * value. + * + * @param value value. + * @return this. + * @throws IOException + */ + public JSONWriter valueFloat(float value) throws IOException + { + beforeValue(); + + mWriter.write(String.valueOf(value)); + return this; + } + + /** + * value. + * + * @param value value. + * @return this. + * @throws IOException + */ + public JSONWriter valueDouble(double value) throws IOException + { + beforeValue(); + + mWriter.write(String.valueOf(value)); + return this; + } + + private void beforeValue() throws IOException + { + switch( mState.type ) + { + case ARRAY: + if( mState.itemCount++ > 0 ) + mWriter.write(JSON.COMMA); + return; + case OBJECT: + throw new IOException("Must call objectItem first."); + case OBJECT_VALUE: + mState.type = OBJECT; + return; + } + } + + private void beforeObjectItem() throws IOException + { + switch( mState.type ) + { + case OBJECT_VALUE: + mWriter.write(JSON.NULL); + case OBJECT: + mState.type = OBJECT_VALUE; + if( mState.itemCount++ > 0 ) + mWriter.write(JSON.COMMA); + return; + default: + throw new IOException("Must call objectBegin first."); + } + } + + private static final String[] CONTROL_CHAR_MAP = new String[]{ + "\\u0000","\\u0001","\\u0002","\\u0003","\\u0004","\\u0005","\\u0006","\\u0007", + "\\b","\\t","\\n","\\u000b","\\f","\\r","\\u000e","\\u000f", + "\\u0010","\\u0011","\\u0012","\\u0013","\\u0014","\\u0015","\\u0016","\\u0017", + "\\u0018","\\u0019","\\u001a","\\u001b","\\u001c","\\u001d","\\u001e","\\u001f" + }; + + private static String escape(String str) + { + if( str == null ) + return str; + int len = str.length(); + if( len == 0 ) + return str; + + char c; + StringBuilder sb = null; + for(int i=0;iJFlex 1.4.3 + * on 7/3/10 3:12 AM from the specification file + * /Users/qianlei/dev/proj/dubbo-1.1/dubbo.common/src/main/java/com/alibaba/dubbo/common/json/json.flex + */ +public class Yylex { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int STR2 = 4; + public static final int STR1 = 2; + public static final int YYINITIAL = 0; + + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 0, 1, 1, 2, 2 + }; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = + "\11\0\1\13\1\13\2\0\1\13\22\0\1\13\1\0\1\10\1\0"+ + "\1\2\2\0\1\11\3\0\1\7\1\43\1\4\1\5\1\14\12\1"+ + "\1\44\6\0\1\33\3\3\1\6\1\32\5\2\1\34\1\2\1\36"+ + "\3\2\1\25\1\35\1\24\1\26\5\2\1\41\1\12\1\42\1\0"+ + "\1\2\1\0\1\27\1\15\2\3\1\23\1\16\5\2\1\30\1\2"+ + "\1\17\3\2\1\20\1\31\1\21\1\22\5\2\1\37\1\0\1\40"+ + "\uff82\0"; + + /** + * Translates characters to character classes + */ + private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\3\0\1\1\1\2\1\3\1\1\1\4\1\5\1\6"+ + "\6\3\1\7\1\10\1\11\1\12\1\13\1\14\1\15"+ + "\1\16\1\0\1\15\3\0\6\3\1\17\1\20\1\21"+ + "\1\22\1\23\1\24\1\25\1\26\1\0\1\27\2\30"+ + "\1\0\6\3\1\0\1\3\1\31\1\32\1\3\1\0"+ + "\1\33\1\0\1\34"; + + private static int [] zzUnpackAction() { + int [] result = new int[63]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\45\0\112\0\157\0\224\0\271\0\336\0\157"+ + "\0\157\0\u0103\0\u0128\0\u014d\0\u0172\0\u0197\0\u01bc\0\u01e1"+ + "\0\157\0\157\0\157\0\157\0\157\0\157\0\u0206\0\157"+ + "\0\u022b\0\u0250\0\u0275\0\u029a\0\u02bf\0\u02e4\0\u0309\0\u032e"+ + "\0\u0353\0\u0378\0\u039d\0\157\0\157\0\157\0\157\0\157"+ + "\0\157\0\157\0\157\0\u03c2\0\157\0\u03e7\0\u040c\0\u040c"+ + "\0\u0431\0\u0456\0\u047b\0\u04a0\0\u04c5\0\u04ea\0\u050f\0\u0534"+ + "\0\271\0\271\0\u0559\0\u057e\0\271\0\u05a3\0\157"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[63]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int ZZ_TRANS [] = { + 3, 4, 5, 5, 6, 3, 5, 3, 7, 8, + 3, 9, 3, 5, 10, 11, 5, 12, 5, 5, + 13, 5, 5, 5, 5, 5, 14, 5, 5, 5, + 15, 16, 17, 18, 19, 20, 21, 22, 22, 22, + 22, 22, 22, 22, 22, 23, 22, 24, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 23, 26, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, + -1, -1, -1, 27, 28, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 28, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 5, 5, 5, -1, + -1, 5, -1, -1, -1, -1, -1, -1, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, + -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, + -1, -1, 5, -1, -1, -1, -1, -1, -1, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 29, + 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, + -1, -1, -1, -1, 5, 5, 5, -1, -1, 5, + -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, + 5, 30, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + -1, 5, 5, 5, -1, -1, 5, -1, -1, -1, + -1, -1, -1, 5, 5, 5, 31, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, + 5, -1, -1, 5, -1, -1, -1, -1, -1, -1, + 5, 5, 5, 5, 5, 5, 5, 5, 32, 5, + 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, + -1, -1, -1, -1, -1, 5, 5, 5, -1, -1, + 5, -1, -1, -1, -1, -1, -1, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 33, 5, 5, 5, -1, -1, -1, -1, -1, + -1, -1, 5, 5, 5, -1, -1, 5, -1, -1, + -1, -1, -1, -1, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 34, 5, 5, 5, 5, 5, 5, + 5, 5, -1, -1, -1, -1, -1, -1, 22, 22, + 22, 22, 22, 22, 22, 22, -1, 22, -1, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, -1, -1, -1, -1, -1, + -1, -1, -1, 35, -1, 36, -1, 37, 38, 39, + 40, 41, 42, 43, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 25, 25, 25, 25, 25, 25, 25, 25, + 25, -1, -1, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 44, 36, + -1, 37, 38, 39, 40, 41, 42, 43, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 46, -1, -1, 47, -1, -1, + 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 5, 5, 5, -1, -1, 5, -1, -1, -1, + -1, -1, -1, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 48, 5, 5, 5, 5, 5, + 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, + 5, -1, -1, 5, -1, -1, -1, -1, -1, -1, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 49, 5, 5, 5, 5, 5, 5, -1, -1, + -1, -1, -1, -1, -1, 5, 5, 5, -1, -1, + 5, -1, -1, -1, -1, -1, -1, 5, 5, 5, + 5, 5, 50, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, + -1, -1, 5, 5, 5, -1, -1, 5, -1, -1, + -1, -1, -1, -1, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 51, 5, 5, 5, 5, 5, 5, + 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, + 5, 5, -1, -1, 5, -1, -1, -1, -1, -1, + -1, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 52, 5, 5, -1, + -1, -1, -1, -1, -1, -1, 5, 5, 5, -1, + -1, 5, -1, -1, -1, -1, -1, -1, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 53, 5, 5, -1, -1, -1, -1, + -1, -1, -1, 54, -1, 54, -1, -1, 54, -1, + -1, -1, -1, -1, -1, 54, 54, -1, -1, -1, + -1, 54, -1, -1, -1, 54, -1, -1, 54, 54, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 45, -1, -1, -1, -1, 28, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 28, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 5, 5, 5, -1, -1, 5, + -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 55, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + -1, 5, 5, 5, -1, -1, 5, -1, -1, -1, + -1, -1, -1, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 56, 5, 5, 5, 5, 5, + 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, + 5, -1, -1, 5, -1, -1, -1, -1, -1, -1, + 5, 5, 5, 5, 5, 5, 57, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, + -1, -1, -1, -1, -1, 5, 5, 5, -1, -1, + 57, -1, -1, -1, -1, -1, -1, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, + -1, -1, 5, 5, 5, -1, -1, 5, -1, -1, + -1, -1, -1, -1, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 58, 5, -1, -1, -1, -1, -1, -1, -1, 5, + 5, 5, -1, -1, 5, -1, -1, -1, -1, -1, + -1, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 56, 5, 5, -1, + -1, -1, -1, -1, -1, -1, 59, -1, 59, -1, + -1, 59, -1, -1, -1, -1, -1, -1, 59, 59, + -1, -1, -1, -1, 59, -1, -1, -1, 59, -1, + -1, 59, 59, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 5, 5, 5, -1, -1, 5, -1, + -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 60, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, + 5, 5, 5, -1, -1, 60, -1, -1, -1, -1, + -1, -1, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + -1, -1, -1, -1, -1, -1, -1, 61, -1, 61, + -1, -1, 61, -1, -1, -1, -1, -1, -1, 61, + 61, -1, -1, -1, -1, 61, -1, -1, -1, 61, + -1, -1, 61, 61, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 62, -1, 62, -1, -1, 62, + -1, -1, -1, -1, -1, -1, 62, 62, -1, -1, + -1, -1, 62, -1, -1, -1, 62, -1, -1, 62, + 62, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = { + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\3\0\1\11\3\1\2\11\7\1\6\11\1\1\1\11"+ + "\1\0\1\1\3\0\6\1\10\11\1\0\1\11\2\1"+ + "\1\0\6\1\1\0\4\1\1\0\1\1\1\0\1\11"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[63]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** number of newlines encountered up to the start of the matched text */ + //private int yyline; + + /** the number of characters up to the start of the matched text */ + //private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + //private int yycolumn; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + //private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + /** denotes if the user-EOF-code has already been executed */ + //private boolean zzEOFDone; + + /* user code: */ +private StringBuffer sb; + + + /** + * Creates a new scanner + * There is also a java.io.InputStream version of this constructor. + * + * @param in the java.io.Reader to read input from. + */ + Yylex(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Creates a new scanner. + * There is also java.io.Reader version of this constructor. + * + * @param in the java.io.Inputstream to read input from. + */ + Yylex(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + char [] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 122) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + + /* first: make room (if you can) */ + if (zzStartRead > 0) { + System.arraycopy(zzBuffer, zzStartRead, + zzBuffer, 0, + zzEndRead-zzStartRead); + + /* translate stored positions */ + zzEndRead-= zzStartRead; + zzCurrentPos-= zzStartRead; + zzMarkedPos-= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[zzCurrentPos*2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = zzReader.read(zzBuffer, zzEndRead, + zzBuffer.length-zzEndRead); + + if (numRead > 0) { + zzEndRead+= numRead; + return false; + } + // unlikely but not impossible: read 0 characters, but not at end of stream + if (numRead == 0) { + int c = zzReader.read(); + if (c == -1) { + return true; + } else { + zzBuffer[zzEndRead++] = (char) c; + return false; + } + } + + // numRead < 0 + return true; + } + + + /** + * Closes the input stream. + */ + public final void yyclose() throws java.io.IOException { + zzAtEOF = true; /* indicate end of file */ + zzEndRead = zzStartRead; /* invalidate buffer */ + + if (zzReader != null) + zzReader.close(); + } + + + /** + * Resets the scanner to read from a new input stream. + * Does not close the old reader. + * + * All internal variables are reset, the old input stream + * cannot be reused (internal buffer is discarded and lost). + * Lexical state is set to ZZ_INITIAL. + * + * @param reader the new input stream + */ + public final void yyreset(java.io.Reader reader) { + zzReader = reader; + //zzAtBOL = true; + zzAtEOF = false; + //zzEOFDone = false; + zzEndRead = zzStartRead = 0; + zzCurrentPos = zzMarkedPos = 0; + //yyline = yychar = yycolumn = 0; + zzLexicalState = YYINITIAL; + } + + + /** + * Returns the current lexical state. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + public final String yytext() { + return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer[zzStartRead+pos]; + } + + + /** + * Returns the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + */ + public JSONToken yylex() throws java.io.IOException, ParseException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char [] zzBufferL = zzBuffer; + char [] zzCMapL = ZZ_CMAP; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = ZZ_LEXSTATE[zzLexicalState]; + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = zzBufferL[zzCurrentPosL++]; + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = zzBufferL[zzCurrentPosL++]; + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 25: + { return new JSONToken(JSONToken.NULL, null); + } + case 29: break; + case 13: + { sb.append(yytext()); + } + case 30: break; + case 18: + { sb.append('\b'); + } + case 31: break; + case 9: + { return new JSONToken(JSONToken.LSQUARE); + } + case 32: break; + case 2: + { Long val = Long.valueOf(yytext()); return new JSONToken(JSONToken.INT, val); + } + case 33: break; + case 16: + { sb.append('\\'); + } + case 34: break; + case 8: + { return new JSONToken(JSONToken.RBRACE); + } + case 35: break; + case 26: + { return new JSONToken(JSONToken.BOOL, Boolean.TRUE); + } + case 36: break; + case 23: + { sb.append('\''); + } + case 37: break; + case 5: + { sb = new StringBuffer(); yybegin(STR2); + } + case 38: break; + case 27: + { return new JSONToken(JSONToken.BOOL, Boolean.FALSE); + } + case 39: break; + case 12: + { return new JSONToken(JSONToken.COLON); + } + case 40: break; + case 21: + { sb.append('\r'); + } + case 41: break; + case 3: + { return new JSONToken(JSONToken.IDENT, yytext()); + } + case 42: break; + case 28: + { try{ sb.append((char)Integer.parseInt(yytext().substring(2),16)); }catch(Exception e){ throw new ParseException(e.getMessage()); } + } + case 43: break; + case 10: + { return new JSONToken(JSONToken.RSQUARE); + } + case 44: break; + case 17: + { sb.append('/'); + } + case 45: break; + case 11: + { return new JSONToken(JSONToken.COMMA); + } + case 46: break; + case 15: + { sb.append('"'); + } + case 47: break; + case 24: + { Double val = Double.valueOf(yytext()); return new JSONToken(JSONToken.FLOAT, val); + } + case 48: break; + case 1: + { throw new ParseException("Unexpected char [" + yytext() +"]"); + } + case 49: break; + case 19: + { sb.append('\f'); + } + case 50: break; + case 7: + { return new JSONToken(JSONToken.LBRACE); + } + case 51: break; + case 14: + { yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); + } + case 52: break; + case 22: + { sb.append('\t'); + } + case 53: break; + case 4: + { sb = new StringBuffer(); yybegin(STR1); + } + case 54: break; + case 20: + { sb.append('\n'); + } + case 55: break; + case 6: + { + } + case 56: break; + default: + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + return null; + } + else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/json.flex b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/json.flex new file mode 100644 index 0000000000..c6d4015aaf --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/json/json.flex @@ -0,0 +1,68 @@ +package com.alibaba.dubbo.common.json; +%% + +%{ +private StringBuffer sb; +%} + +%table +%unicode +%state STR1,STR2 + +%yylexthrow ParseException + +HEX = [a-fA-F0-9] +HEX4 = {HEX}{HEX}{HEX}{HEX} + +IDENT = [a-zA-Z_$] [a-zA-Z0-9_$]* +INT_LITERAL = [-]? [0-9]+ +FLOAT_LITERAL = {INT_LITERAL} ( ( \.[0-9]+ ) ? ( [eE][-+]? [0-9]+ )? ) + +ESC1 = [^\"\\] +ESC2 = [^\'\\] + +SKIP = [ \t\r\n] +OTHERS = . +%% + +{ + \" { yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); } + {ESC1}+ { sb.append(yytext()); } + \\\" { sb.append('"'); } +} + +{ + \' { yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); } + {ESC2}+ { sb.append(yytext()); } + \\\' { sb.append('\''); } +} + +{ + \\\\ { sb.append('\\'); } + \\\/ { sb.append('/'); } + \\b { sb.append('\b'); } + \\f { sb.append('\f'); } + \\n { sb.append('\n'); } + \\r { sb.append('\r'); } + \\t { sb.append('\t'); } + \\u{HEX4} { try{ sb.append((char)Integer.parseInt(yytext().substring(2),16)); }catch(Exception e){ throw new ParseException(e.getMessage()); } } +} + +{ + \" { sb = new StringBuffer(); yybegin(STR1); } + \' { sb = new StringBuffer(); yybegin(STR2); } + {INT_LITERAL} { Long val = Long.valueOf(yytext()); return new JSONToken(JSONToken.INT, val); } + {FLOAT_LITERAL} { Double val = Double.valueOf(yytext()); return new JSONToken(JSONToken.FLOAT, val); } + "true"|"TRUE" { return new JSONToken(JSONToken.BOOL, Boolean.TRUE); } + "false"|"FALSE" { return new JSONToken(JSONToken.BOOL, Boolean.FALSE); } + "null"|"NULL" { return new JSONToken(JSONToken.NULL, null); } + {IDENT} { return new JSONToken(JSONToken.IDENT, yytext()); } + "{" { return new JSONToken(JSONToken.LBRACE); } + "}" { return new JSONToken(JSONToken.RBRACE); } + "[" { return new JSONToken(JSONToken.LSQUARE); } + "]" { return new JSONToken(JSONToken.RSQUARE); } + "," { return new JSONToken(JSONToken.COMMA); } + ":" { return new JSONToken(JSONToken.COLON); } + {SKIP}+ {} + {OTHERS} { throw new ParseException("Unexpected char [" + yytext() +"]"); } +} diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/Level.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/Level.java new file mode 100644 index 0000000000..f1a18346c4 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/Level.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger; + +public enum Level { + + ALL, + + TRACE, + + DEBUG, + + INFO, + + WARN, + + ERROR, + + OFF + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/Logger.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/Logger.java new file mode 100644 index 0000000000..9901387e60 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/Logger.java @@ -0,0 +1,164 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger; + +/** + * 日志接口

    声明:引用自commons-logging + * + * @author liangfei0201@163.com + * + */ +public interface Logger { + + /** + * 输出跟踪信息 + * + * @param msg 信息内容 + */ + public void trace(String msg); + + /** + * 输出跟踪信息 + * + * @param e 异常信息 + */ + public void trace(Throwable e); + + /** + * 输出跟踪信息 + * + * @param msg 信息内容 + * @param e 异常信息 + */ + public void trace(String msg, Throwable e); + + /** + * 输出调试信息 + * + * @param msg 信息内容 + */ + public void debug(String msg); + + /** + * 输出调试信息 + * + * @param e 异常信息 + */ + public void debug(Throwable e); + + /** + * 输出调试信息 + * + * @param msg 信息内容 + * @param e 异常信息 + */ + public void debug(String msg, Throwable e); + + /** + * 输出普通信息 + * + * @param msg 信息内容 + */ + public void info(String msg); + + /** + * 输出普通信息 + * + * @param e 异常信息 + */ + public void info(Throwable e); + + /** + * 输出普通信息 + * + * @param msg 信息内容 + * @param e 异常信息 + */ + public void info(String msg, Throwable e); + + /** + * 输出警告信息 + * + * @param msg 信息内容 + */ + public void warn(String msg); + + /** + * 输出警告信息 + * + * @param msg e 异常信息 + */ + public void warn(Throwable e); + + /** + * 输出警告信息 + * + * @param msg 信息内容 + * @param e 异常信息 + */ + public void warn(String msg, Throwable e); + + /** + * 输出错误信息 + * + * @param msg 信息内容 + */ + public void error(String msg); + + /** + * 输出错误信息 + * + * @param e 异常信息 + */ + public void error(Throwable e); + + /** + * 输出错误信息 + * + * @param msg 信息内容 + * @param e 异常信息 + */ + public void error(String msg, Throwable e); + + /** + * 跟踪信息是否开启 + * + * @return 是否开启 + */ + public boolean isTraceEnabled(); + + /** + * 调试信息是否开启 + * + * @return 是否开启 + */ + public boolean isDebugEnabled(); + + /** + * 普通信息是否开启 + * + * @return 是否开启 + */ + public boolean isInfoEnabled(); + + /** + * 警告信息是否开启 + * + * @return 是否开启 + */ + public boolean isWarnEnabled(); + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/LoggerFactory.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/LoggerFactory.java new file mode 100644 index 0000000000..57ba943c81 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/LoggerFactory.java @@ -0,0 +1,109 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger; + +import java.io.File; + +import com.alibaba.dubbo.common.logger.support.FailsafeLogger; +import com.alibaba.dubbo.common.logger.support.JdkLoggerFactory; +import com.alibaba.dubbo.common.logger.support.Log4jLoggerFactory; + +/** + * 日志输出器工厂 + * + * @author liangfei0201@163.com + * + */ +public class LoggerFactory { + + private LoggerFactory() { + } + + private static volatile LoggerFactorySupport LOGGER_FACTORY; + + // 查找常用的日志框架 + static { + try { + setLoggerFactory(new Log4jLoggerFactory()); + } catch (Throwable e1) { + setLoggerFactory(new JdkLoggerFactory()); + } + } + + /** + * 设置日志输出器供给器 + * + * @param loggerFactory + * 日志输出器供给器 + */ + public static void setLoggerFactory(LoggerFactorySupport loggerFactory) { + if (loggerFactory != null) { + Logger logger = loggerFactory.getLogger(LoggerFactory.class.getName()); + logger.info("using logger: " + loggerFactory.getClass().getName()); + LoggerFactory.LOGGER_FACTORY = loggerFactory; + } + } + + /** + * 获取日志输出器 + * + * @param key + * 分类键 + * @return 日志输出器, 后验条件: 不返回null. + */ + public static Logger getLogger(Class key) { + return new FailsafeLogger(LOGGER_FACTORY.getLogger(key)); + } + + /** + * 获取日志输出器 + * + * @param key + * 分类键 + * @return 日志输出器, 后验条件: 不返回null. + */ + public static Logger getLogger(String key) { + return new FailsafeLogger(LOGGER_FACTORY.getLogger(key)); + } + + /** + * 动态设置输出日志级别 + * + * @param level 日志级别 + */ + public static void setLevel(Level level) { + LOGGER_FACTORY.setLevel(level); + } + + /** + * 获取日志级别 + * + * @return 日志级别 + */ + public static Level getLevel() { + return LOGGER_FACTORY.getLevel(); + } + + /** + * 获取日志文件 + * + * @return 日志文件 + */ + public static File getFile() { + return LOGGER_FACTORY.getFile(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/LoggerFactorySupport.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/LoggerFactorySupport.java new file mode 100644 index 0000000000..b03226b3ee --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/LoggerFactorySupport.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger; + +import java.io.File; + + +/** + * 日志输出器供给器 + * + * @author liangfei0201@163.com + * + */ +public interface LoggerFactorySupport { + + /** + * 获取日志输出器 + * + * @param key 分类键 + * @return 日志输出器, 后验条件: 不返回null. + */ + Logger getLogger(Class key); + + /** + * 获取日志输出器 + * + * @param key 分类键 + * @return 日志输出器, 后验条件: 不返回null. + */ + Logger getLogger(String key); + + /** + * 设置输出等级 + * + * @param level + */ + void setLevel(Level level); + + /** + * + * @return + */ + Level getLevel(); + + /** + * + * @return + */ + File getFile(); + + /** + * + * @param file + */ + void setFile(File file); + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/FailsafeLogger.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/FailsafeLogger.java new file mode 100644 index 0000000000..4ff5e4c981 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/FailsafeLogger.java @@ -0,0 +1,165 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger.support; + +import com.alibaba.dubbo.common.logger.Logger; + +public class FailsafeLogger implements Logger { + + private final Logger logger; + + public FailsafeLogger(Logger logger) { + this.logger = logger; + } + + public void trace(String msg, Throwable e) { + try { + logger.trace(msg, e); + } catch (Throwable t) { + } + } + + public void trace(Throwable e) { + try { + logger.trace(e); + } catch (Throwable t) { + } + } + + public void trace(String msg) { + try { + logger.trace(msg); + } catch (Throwable t) { + } + } + + public void debug(String msg, Throwable e) { + try { + logger.debug(msg, e); + } catch (Throwable t) { + } + } + + public void debug(Throwable e) { + try { + logger.debug(e); + } catch (Throwable t) { + } + } + + public void debug(String msg) { + try { + logger.debug(msg); + } catch (Throwable t) { + } + } + + public void info(String msg, Throwable e) { + try { + logger.info(msg, e); + } catch (Throwable t) { + } + } + + public void info(String msg) { + try { + logger.info(msg); + } catch (Throwable t) { + } + } + + public void warn(String msg, Throwable e) { + try { + logger.warn(msg, e); + } catch (Throwable t) { + } + } + + public void warn(String msg) { + try { + logger.warn(msg); + } catch (Throwable t) { + } + } + + public void error(String msg, Throwable e) { + try { + logger.error(msg, e); + } catch (Throwable t) { + } + } + + public void error(String msg) { + try { + logger.error(msg); + } catch (Throwable t) { + } + } + + public void error(Throwable e) { + try { + logger.error(e); + } catch (Throwable t) { + } + } + + public void info(Throwable e) { + try { + logger.info(e); + } catch (Throwable t) { + } + } + + public void warn(Throwable e) { + try { + logger.warn(e); + } catch (Throwable t) { + } + } + + public boolean isTraceEnabled() { + try { + return logger.isTraceEnabled(); + } catch (Throwable t) { + return false; + } + } + + public boolean isDebugEnabled() { + try { + return logger.isDebugEnabled(); + } catch (Throwable t) { + return false; + } + } + + public boolean isInfoEnabled() { + try { + return logger.isInfoEnabled(); + } catch (Throwable t) { + return false; + } + } + + public boolean isWarnEnabled() { + try { + return logger.isWarnEnabled(); + } catch (Throwable t) { + return false; + } + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/JdkLogger.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/JdkLogger.java new file mode 100644 index 0000000000..34adbeb752 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/JdkLogger.java @@ -0,0 +1,110 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger.support; + +import java.util.logging.Level; + +import com.alibaba.dubbo.common.logger.Logger; + +public class JdkLogger implements Logger { + + private final java.util.logging.Logger logger; + + public JdkLogger(java.util.logging.Logger logger) { + this.logger = logger; + } + + public void trace(String msg) { + logger.log(Level.FINER, msg); + } + + public void trace(Throwable e) { + logger.log(Level.FINER, e.getMessage(), e); + } + + public void trace(String msg, Throwable e) { + logger.log(Level.FINER, msg, e); + } + + public void debug(String msg) { + logger.log(Level.FINE, msg); + } + + public void debug(Throwable e) { + logger.log(Level.FINE, e.getMessage(), e); + } + + public void debug(String msg, Throwable e) { + logger.log(Level.FINE, msg, e); + } + + public void info(String msg) { + logger.log(Level.INFO, msg); + } + + public void info(String msg, Throwable e) { + logger.log(Level.INFO, msg, e); + } + + public void warn(String msg) { + logger.log(Level.WARNING, msg); + } + + public void warn(String msg, Throwable e) { + logger.log(Level.WARNING, msg, e); + } + + public void error(String msg) { + logger.log(Level.SEVERE, msg); + } + + public void error(String msg, Throwable e) { + logger.log(Level.SEVERE, msg, e); + } + + public void error(Throwable e) { + logger.log(Level.SEVERE, e.getMessage(), e); + } + + public void info(Throwable e) { + logger.log(Level.INFO, e.getMessage(), e); + } + + public void warn(Throwable e) { + logger.log(Level.WARNING, e.getMessage(), e); + } + + public boolean isTraceEnabled() { + return logger.isLoggable(Level.FINER); + } + + public boolean isDebugEnabled() { + return logger.isLoggable(Level.FINE); + } + + public boolean isInfoEnabled() { + return logger.isLoggable(Level.INFO); + } + + public boolean isWarnEnabled() { + return logger.isLoggable(Level.WARNING); + } + + public boolean isErrorEnabled() { + return logger.isLoggable(Level.SEVERE); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/JdkLoggerFactory.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/JdkLoggerFactory.java new file mode 100644 index 0000000000..6acd00ede3 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/JdkLoggerFactory.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger.support; + +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.LogManager; + +import com.alibaba.dubbo.common.logger.Level; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactorySupport; + +public class JdkLoggerFactory implements LoggerFactorySupport { + + private static final String GLOBAL_LOGGER_NAME = "global"; + + private File file; + + public JdkLoggerFactory() { + try { + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.properties"); + if (in != null) { + LogManager.getLogManager().readConfiguration(in); + } else { + System.err.println("No such logging.properties in classpath for jdk logging config!"); + } + } catch (Throwable t) { + System.err.println("Failed to load logging.properties in classpath for jdk logging config, cause: " + t.getMessage()); + } + try { + Handler[] handlers = java.util.logging.Logger.getLogger(GLOBAL_LOGGER_NAME).getHandlers(); + for (Handler handler : handlers) { + if (handler instanceof FileHandler) { + FileHandler fileHandler = (FileHandler)handler; + Field field = fileHandler.getClass().getField("files"); + File[] files = (File[])field.get(fileHandler); + if (files != null && files.length > 0) { + file = files[0]; + } + } + } + } catch (Throwable t) { + } + } + + public Logger getLogger(Class key) { + return new JdkLogger(java.util.logging.Logger.getLogger(key == null ? "" : key.getName())); + } + + public Logger getLogger(String key) { + return new JdkLogger(java.util.logging.Logger.getLogger(key)); + } + + public void setLevel(Level level) { + java.util.logging.Logger.getLogger(GLOBAL_LOGGER_NAME).setLevel(toJdkLevel(level)); + } + + public Level getLevel() { + return fromJdkLevel(java.util.logging.Logger.getLogger(GLOBAL_LOGGER_NAME).getLevel()); + } + + public File getFile() { + return file; + } + + private static java.util.logging.Level toJdkLevel(Level level) { + if (level == Level.ALL) + return java.util.logging.Level.ALL; + if (level == Level.TRACE) + return java.util.logging.Level.FINER; + if (level == Level.DEBUG) + return java.util.logging.Level.FINE; + if (level == Level.INFO) + return java.util.logging.Level.INFO; + if (level == Level.WARN) + return java.util.logging.Level.WARNING; + if (level == Level.ERROR) + return java.util.logging.Level.SEVERE; + // if (level == Level.OFF) + return java.util.logging.Level.OFF; + } + + private static Level fromJdkLevel(java.util.logging.Level level) { + if (level == java.util.logging.Level.ALL) + return Level.ALL; + if (level == java.util.logging.Level.FINER) + return Level.TRACE; + if (level == java.util.logging.Level.FINE) + return Level.DEBUG; + if (level == java.util.logging.Level.INFO) + return Level.INFO; + if (level == java.util.logging.Level.WARNING) + return Level.WARN; + if (level == java.util.logging.Level.SEVERE) + return Level.ERROR; + // if (level == java.util.logging.Level.OFF) + return Level.OFF; + } + + public void setFile(File file) { + + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/Log4jLogger.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/Log4jLogger.java new file mode 100644 index 0000000000..519a36fed9 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/Log4jLogger.java @@ -0,0 +1,108 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger.support; + +import org.apache.log4j.Level; + +import com.alibaba.dubbo.common.logger.Logger; + +public class Log4jLogger implements Logger { + + private static final String FQCN = FailsafeLogger.class.getName(); + + private final org.apache.log4j.Logger logger; + + public Log4jLogger(org.apache.log4j.Logger logger) { + this.logger = logger; + } + + public void trace(String msg) { + logger.log(FQCN, Level.TRACE, msg, null); + } + + public void trace(Throwable e) { + logger.log(FQCN, Level.TRACE, e == null ? null : e.getMessage(), e); + } + + public void trace(String msg, Throwable e) { + logger.log(FQCN, Level.TRACE, msg, e); + } + + public void debug(String msg) { + logger.log(FQCN, Level.DEBUG, msg, null); + } + + public void debug(Throwable e) { + logger.log(FQCN, Level.DEBUG, e == null ? null : e.getMessage(), e); + } + + public void debug(String msg, Throwable e) { + logger.log(FQCN, Level.DEBUG, msg, e); + } + + public void info(String msg) { + logger.log(FQCN, Level.INFO, msg, null); + } + + public void info(Throwable e) { + logger.log(FQCN, Level.INFO, e == null ? null : e.getMessage(), e); + } + + public void info(String msg, Throwable e) { + logger.log(FQCN, Level.INFO, msg, e); + } + + public void warn(String msg) { + logger.log(FQCN, Level.WARN, msg, null); + } + + public void warn(Throwable e) { + logger.log(FQCN, Level.WARN, e == null ? null : e.getMessage(), e); + } + + public void warn(String msg, Throwable e) { + logger.log(FQCN, Level.WARN, msg, e); + } + + public void error(String msg) { + logger.log(FQCN, Level.ERROR, msg, null); + } + + public void error(Throwable e) { + logger.log(FQCN, Level.ERROR, e == null ? null : e.getMessage(), e); + } + + public void error(String msg, Throwable e) { + logger.log(FQCN, Level.ERROR, msg, e); + } + + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + public boolean isWarnEnabled() { + return logger.isEnabledFor(Level.WARN); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/Log4jLoggerFactory.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/Log4jLoggerFactory.java new file mode 100644 index 0000000000..1a84d62d9a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/logger/support/Log4jLoggerFactory.java @@ -0,0 +1,113 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.logger.support; + +import java.io.File; +import java.util.Enumeration; + +import org.apache.log4j.Appender; +import org.apache.log4j.FileAppender; +import org.apache.log4j.LogManager; + +import com.alibaba.dubbo.common.logger.Level; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactorySupport; + +public class Log4jLoggerFactory implements LoggerFactorySupport { + + private File file; + + @SuppressWarnings("unchecked") + public Log4jLoggerFactory() { + try { + org.apache.log4j.Logger logger = LogManager.getRootLogger(); + if (logger != null) { + Enumeration appenders = logger.getAllAppenders(); + if (appenders != null) { + while (appenders.hasMoreElements()) { + Appender appender = appenders.nextElement(); + if (appender instanceof FileAppender) { + FileAppender fileAppender = (FileAppender)appender; + String filename = fileAppender.getFile(); + file = new File(filename); + break; + } + } + } + } + } catch (Throwable t) { + } + } + + public Logger getLogger(Class key) { + return new Log4jLogger(LogManager.getLogger(key)); + } + + public Logger getLogger(String key) { + return new Log4jLogger(LogManager.getLogger(key)); + } + + public void setLevel(Level level) { + LogManager.getRootLogger().setLevel(toLog4jLevel(level)); + } + + public Level getLevel() { + return fromLog4jLevel(LogManager.getRootLogger().getLevel()); + } + + public File getFile() { + return file; + } + + private static org.apache.log4j.Level toLog4jLevel(Level level) { + if (level == Level.ALL) + return org.apache.log4j.Level.ALL; + if (level == Level.TRACE) + return org.apache.log4j.Level.TRACE; + if (level == Level.DEBUG) + return org.apache.log4j.Level.DEBUG; + if (level == Level.INFO) + return org.apache.log4j.Level.INFO; + if (level == Level.WARN) + return org.apache.log4j.Level.WARN; + if (level == Level.ERROR) + return org.apache.log4j.Level.ERROR; + // if (level == Level.OFF) + return org.apache.log4j.Level.OFF; + } + + private static Level fromLog4jLevel(org.apache.log4j.Level level) { + if (level == org.apache.log4j.Level.ALL) + return Level.ALL; + if (level == org.apache.log4j.Level.TRACE) + return Level.TRACE; + if (level == org.apache.log4j.Level.DEBUG) + return Level.DEBUG; + if (level == org.apache.log4j.Level.INFO) + return Level.INFO; + if (level == org.apache.log4j.Level.WARN) + return Level.WARN; + if (level == org.apache.log4j.Level.ERROR) + return Level.ERROR; + // if (level == org.apache.log4j.Level.OFF) + return Level.OFF; + } + + public void setFile(File file) { + + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/DataInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/DataInput.java new file mode 100644 index 0000000000..68d6a2634a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/DataInput.java @@ -0,0 +1,98 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize; + +import java.io.IOException; + +/** + * Data input. + * + * @author qian.lei + */ +public interface DataInput { + + /** + * Read boolean. + * + * @return boolean. + * @throws IOException. + */ + boolean readBool() throws IOException; + + /** + * Read byte. + * + * @return byte value. + * @throws IOException. + */ + byte readByte() throws IOException; + + /** + * Read short integer. + * + * @return short. + * @throws IOException. + */ + short readShort() throws IOException; + + /** + * Read integer. + * + * @return integer. + * @throws IOException. + */ + int readInt() throws IOException; + + /** + * Read long. + * + * @return long. + * @throws IOException. + */ + long readLong() throws IOException; + + /** + * Read float. + * + * @return float. + * @throws IOException. + */ + float readFloat() throws IOException; + + /** + * Read double. + * + * @return double. + * @throws IOException. + */ + double readDouble() throws IOException; + + /** + * Read UTF-8 string. + * + * @return string. + * @throws IOException. + */ + String readUTF() throws IOException; + + /** + * Read byte array. + * + * @return byte array. + * @throws IOException. + */ + byte[] readBytes() throws IOException; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/DataOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/DataOutput.java new file mode 100644 index 0000000000..64a42411b2 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/DataOutput.java @@ -0,0 +1,116 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize; + +import java.io.IOException; + +/** + * Data output. + * + * @author qian.lei + */ +public interface DataOutput { + + /** + * Write boolean. + * + * @param v value. + * @throws IOException. + */ + void writeBool(boolean v) throws IOException; + + /** + * Write byte. + * + * @param v value. + * @throws IOException. + */ + void writeByte(byte v) throws IOException; + + /** + * Write short. + * + * @param v value. + * @throws IOException. + */ + void writeShort(short v) throws IOException; + + /** + * Write integer. + * + * @param v value. + * @throws IOException. + */ + void writeInt(int v) throws IOException; + + /** + * Write long. + * + * @param v value. + * @throws IOException. + */ + void writeLong(long v) throws IOException; + + /** + * Write float. + * + * @param v value. + * @throws IOException. + */ + void writeFloat(float v) throws IOException; + + /** + * Write double. + * + * @param v value. + * @throws IOException. + */ + void writeDouble(double v) throws IOException; + + /** + * Write string. + * + * @param v value. + * @throws IOException. + */ + void writeUTF(String v) throws IOException; + + /** + * Write byte array. + * + * @param v value. + * @throws IOException. + */ + void writeBytes(byte[] b) throws IOException; + + /** + * Write byte array. + * + * @param v value. + * @param off offset. + * @param len length. + * @throws IOException. + */ + void writeBytes(byte[] b, int off, int len) throws IOException; + + /** + * Flush buffer. + * + * @param v value. + * @throws IOException. + */ + void flushBuffer() throws IOException; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/ObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/ObjectInput.java new file mode 100644 index 0000000000..e8af0ca49a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/ObjectInput.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize; + +import java.io.IOException; + +/** + * Object input. + * + * @author qian.lei + */ +public interface ObjectInput extends DataInput { + + /** + * read object. + * + * @return object. + */ + Object readObject() throws IOException, ClassNotFoundException; + + /** + * read object. + * + * @param cls object type. + * @return object. + */ + T readObject(Class cls) throws IOException, ClassNotFoundException; + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/ObjectOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/ObjectOutput.java new file mode 100644 index 0000000000..c91d416aab --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/ObjectOutput.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize; + +import java.io.IOException; + +/** + * Object output. + * + * @author qian.lei + */ +public interface ObjectOutput extends DataOutput { + + /** + * write object. + * + * @param obj object. + */ + void writeObject(Object obj) throws IOException; + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/Serialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/Serialization.java new file mode 100644 index 0000000000..03af2a416c --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/Serialization.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * Serialization. (SPI, Singleton, ThreadSafe) + * + * @author ding.lid + * @author william.liangf + */ +@Extension("hessian2") +public interface Serialization { + + /** + * get content type id + * + * @return + */ + byte getContentTypeId(); + + /** + * get content type + * + * @return content type + */ + String getContentType(); + + /** + * create serializer + * @param url + * @param output + * @return serializer + * @throws IOException + */ + @Adaptive + ObjectOutput serialize(URL url, OutputStream output) throws IOException; + + /** + * create deserializer + * @param url + * @param input + * @return deserializer + * @throws IOException + */ + @Adaptive + ObjectInput deserialize(URL url, InputStream input) throws IOException; + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/Builder.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/Builder.java new file mode 100644 index 0000000000..3fefb7c68b --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/Builder.java @@ -0,0 +1,1541 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.dubbo; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.regex.Matcher; + +import com.alibaba.dubbo.common.bytecode.ClassGenerator; +import com.alibaba.dubbo.common.io.ClassDescriptorMapper; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.serialize.support.java.CompactedObjectInputStream; +import com.alibaba.dubbo.common.serialize.support.java.CompactedObjectOutputStream; +import com.alibaba.dubbo.common.utils.ClassHelper; +import com.alibaba.dubbo.common.utils.IOUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * Builder. + * + * @author qian.lei + * + * @param type. + */ + +@SuppressWarnings({ "unchecked", "rawtypes" }) +public abstract class Builder implements GenericDataFlags +{ + // Must be protected. by qian.lei + protected static Logger logger = LoggerFactory.getLogger(Builder.class); + + private static final AtomicLong BUILDER_CLASS_COUNTER = new AtomicLong(0); + + private static final String BUILDER_CLASS_NAME = Builder.class.getName(); + + private static final Map, Builder> BuilderMap = new ConcurrentHashMap, Builder>(); + private static final Map, Builder> nonSerializableBuilderMap = new ConcurrentHashMap, Builder>(); + + private static final String FIELD_CONFIG_SUFFIX = ".fc"; + + private static final int MAX_FIELD_CONFIG_FILE_SIZE = 16 * 1024; + + private static final Comparator FNC = new Comparator(){ + public int compare(String n1, String n2){ return compareFieldName(n1, n2); } + }; + + private static final Comparator FC = new Comparator(){ + public int compare(Field f1, Field f2){ return compareFieldName(f1.getName(), f2.getName()); } + }; + + private static final Comparator CC = new Comparator(){ + public int compare(Constructor o1, Constructor o2){ return o1.getParameterTypes().length - o2.getParameterTypes().length; } + }; + + // class-descriptor mapper + private static final List mDescList = new ArrayList(); + + private static final Map mDescMap = new ConcurrentHashMap(); + + public static ClassDescriptorMapper DEFAULT_CLASS_DESCRIPTOR_MAPPER = new ClassDescriptorMapper(){ + public String getDescriptor(int index) + { + if( index < 0 || index >= mDescList.size() ) + return null; + return mDescList.get(index); + } + + public int getDescriptorIndex(String desc) + { + Integer ret = mDescMap.get(desc); + return ret == null ? -1 : ret.intValue(); + } + }; + + protected Builder(){} + + abstract public Class getType(); + + public void writeTo(T obj, OutputStream os) throws IOException + { + GenericObjectOutput out = new GenericObjectOutput(os); + writeTo(obj, out); + out.flushBuffer(); + } + + public T parseFrom(byte[] b) throws IOException + { + return parseFrom(new UnsafeByteArrayInputStream(b)); + } + + public T parseFrom(InputStream is) throws IOException + { + return parseFrom(new GenericObjectInput(is)); + } + + abstract public void writeTo(T obj, GenericObjectOutput out) throws IOException; + + abstract public T parseFrom(GenericObjectInput in) throws IOException; + + public static Builder register(Class c, boolean isAllowNonSerializable) + { + if( c == Object.class || c.isInterface() ) + return (Builder)GenericBuilder; + if( c == Object[].class ) + return (Builder)GenericArrayBuilder; + + Builder b = (Builder)BuilderMap.get(c); + if(null != b) return b; + + boolean isSerializable = Serializable.class.isAssignableFrom(c); + if(!isAllowNonSerializable && !isSerializable) { + throw new IllegalStateException("Serialized class " + c.getName() + + " must implement java.io.Serializable (dubbo codec setting: isAllowNonSerializable = false)"); + } + + b = (Builder)nonSerializableBuilderMap.get(c); + if(null != b) return b; + + b = newBuilder(c); + if(isSerializable) + BuilderMap.put(c, b); + else + nonSerializableBuilderMap.put(c, b); + + return b; + } + + public static Builder register(Class c) + { + return register(c, false); + } + + public static void register(Class c, Builder b) + { + if(Serializable.class.isAssignableFrom(c)) + BuilderMap.put(c, b); + else + nonSerializableBuilderMap.put(c, b); + } + + private static Builder newBuilder(Class c) + { + if( c.isPrimitive() ) + throw new RuntimeException("Can not create builder for primitive type: " + c); + + if( logger.isInfoEnabled() ) + logger.info("create Builder for class: " + c); + + Builder builder; + if( c.isArray() ) + builder = newArrayBuilder(c); + else + builder = newObjectBuilder(c); + return (Builder)builder; + } + + private static Builder newArrayBuilder(Class c) + { + Class cc = c.getComponentType(); + if( cc.isInterface() ) + return GenericArrayBuilder; + + ClassLoader cl = ClassHelper.getClassLoader(c); + + String cn = ReflectUtils.getName(c), ccn = ReflectUtils.getName(cc); // get class name as int[][], double[]. + String bcn = BUILDER_CLASS_NAME + "$bc" + BUILDER_CLASS_COUNTER.getAndIncrement(); + + int ix = cn.indexOf(']'); + String s1 = cn.substring(0, ix), s2 = cn.substring(ix); // if name='int[][]' then s1='int[', s2='][]' + + StringBuilder cwt = new StringBuilder("public void writeTo(Object obj, ").append(GenericObjectOutput.class.getName()).append(" out) throws java.io.IOException{"); // writeTo code. + StringBuilder cpf = new StringBuilder("public Object parseFrom(").append(GenericObjectInput.class.getName()).append(" in) throws java.io.IOException{"); // parseFrom code. + + cwt.append("if( $1 == null ){ $2.write0(OBJECT_NULL); return; }"); + cwt.append(cn).append(" v = (").append(cn).append(")$1; int len = v.length; $2.write0(OBJECT_VALUES); $2.writeUInt(len); for(int i=0;i builder = null; + if( cc.isPrimitive() ) + { + if( cc == boolean.class ) + { + cwt.append("$2.writeBool(v[i]);"); + cpf.append("ret[i] = $1.readBool();"); + } + else if( cc == byte.class ) + { + cwt.append("$2.writeByte(v[i]);"); + cpf.append("ret[i] = $1.readByte();"); + } + else if( cc == char.class ) + { + cwt.append("$2.writeShort((short)v[i]);"); + cpf.append("ret[i] = (char)$1.readShort();"); + } + else if( cc == short.class ) + { + cwt.append("$2.writeShort(v[i]);"); + cpf.append("ret[i] = $1.readShort();"); + } + else if( cc == int.class ) + { + cwt.append("$2.writeInt(v[i]);"); + cpf.append("ret[i] = $1.readInt();"); + } + else if( cc == long.class ) + { + cwt.append("$2.writeLong(v[i]);"); + cpf.append("ret[i] = $1.readLong();"); + } + else if( cc == float.class ) + { + cwt.append("$2.writeFloat(v[i]);"); + cpf.append("ret[i] = $1.readFloat();"); + } + else if( cc == double.class ) + { + cwt.append("$2.writeDouble(v[i]);"); + cpf.append("ret[i] = $1.readDouble();"); + } + } + else + { + builder = register(cc); + + cwt.append("builder.writeTo(v[i], $2);"); + cpf.append("ret[i] = (").append(ccn).append(")builder.parseFrom($1);"); + } + cwt.append(" } }"); + cpf.append(" } return ret; }"); + + ClassGenerator cg = ClassGenerator.newInstance(cl); + cg.setClassName(bcn); + cg.setSuperClass(Builder.class); + cg.addDefaultConstructor(); + if( builder != null ) + cg.addField("public static " + BUILDER_CLASS_NAME + " builder;"); + cg.addMethod("public Class getType(){ return " + cn + ".class; }"); + cg.addMethod(cwt.toString()); + cg.addMethod(cpf.toString()); + try + { + Class wc = cg.toClass(); + // set static field. + if( builder != null ) + wc.getField("builder").set(null, builder); + return (Builder)wc.newInstance(); + } + catch(RuntimeException e) + { + throw e; + } + catch(Throwable e) + { + throw new RuntimeException(e.getMessage()); + } + finally + { + cg.release(); + } + } + + private static Builder newObjectBuilder(final Class c) + { + if( c.isEnum() ) + return newEnumBuilder(c); + + if( c.isAnonymousClass() ) + throw new RuntimeException("Can not instantiation anonymous class: " + c); + + if( c.getEnclosingClass() != null && !Modifier.isStatic(c.getModifiers()) ) + throw new RuntimeException("Can not instantiation inner and non-static class: " + c); + + if( Throwable.class.isAssignableFrom(c) ) + return SerializableBuilder; + + ClassLoader cl = ClassHelper.getClassLoader(c); + + // is same package. + boolean isp; + String cn = c.getName(), bcn; + if( c.getClassLoader() == null ) // is system class. if( cn.startsWith("java.") || cn.startsWith("javax.") || cn.startsWith("sun.") ) + { + isp = false; + bcn = BUILDER_CLASS_NAME + "$bc" + BUILDER_CLASS_COUNTER.getAndIncrement(); + } + else + { + isp = true; + bcn = cn + "$bc" + BUILDER_CLASS_COUNTER.getAndIncrement(); + } + + // is Collection, is Map, is Serializable. + boolean isc = Collection.class.isAssignableFrom(c); + boolean ism = !isc && Map.class.isAssignableFrom(c); + boolean iss = !( isc || ism ) && Serializable.class.isAssignableFrom(c); + + // deal with fields. + String[] fns = null; // fix-order fields names + InputStream is = c.getResourceAsStream(c.getSimpleName() + FIELD_CONFIG_SUFFIX); // load field-config file. + if( is != null ) + { + try + { + int len = is.available(); + if( len > 0 ) + { + if( len > MAX_FIELD_CONFIG_FILE_SIZE ) + throw new RuntimeException("Load [" + c.getName() + "] field-config file error: File-size too larger"); + + String[] lines = IOUtils.readLines(is); + if( lines != null && lines.length > 0 ) + { + List list = new ArrayList(); + for(int i=0;i t = c; + List fl = new ArrayList(); + do + { + fs = t.getDeclaredFields(); + for( Field tf : fs ) + { + int mod = tf.getModifiers(); + if( Modifier.isStatic(mod) || Modifier.isFinal(mod) || tf.getName().equals("this$0") ) // skip static or inner-class's 'this$0' field. + continue; + if( Modifier.isTransient(mod) ) + { + if( iss ) + return SerializableBuilder; + continue; + } + tf.setAccessible(true); + fl.add(tf); + } + t = t.getSuperclass(); + } + while( t != Object.class ); + + fs = fl.toArray(new Field[0]); + if( fs.length > 1 ) + Arrays.sort(fs, FC); + } + + // deal with constructors. + Constructor[] cs = c.getDeclaredConstructors(); + if( cs.length == 0 ) + { + Class t = c; + do + { + t = t.getSuperclass(); + if( t == null ) + throw new RuntimeException("Can not found Constructor?"); + cs = c.getDeclaredConstructors(); + } + while( cs.length == 0 ); + } + if( cs.length > 1 ) + Arrays.sort(cs, CC); + + // writeObject code. + StringBuilder cwf = new StringBuilder("protected void writeObject(Object obj, ").append(GenericObjectOutput.class.getName()).append(" out) throws java.io.IOException{"); + cwf.append(cn).append(" v = (").append(cn).append(")$1; "); + cwf.append("$2.writeInt(fields.length);"); + + // readObject code. + StringBuilder crf = new StringBuilder("protected void readObject(Object ret, ").append(GenericObjectInput.class.getName()).append(" in) throws java.io.IOException{"); + crf.append("int fc = $2.readInt();"); + crf.append("if( fc != ").append(fs.length).append(" ) throw new IllegalStateException(\"Deserialize Class [").append(cn).append("], field count not matched. Expect ").append(fs.length).append(" but get \" + fc +\".\");"); + crf.append(cn).append(" ret = (").append(cn).append(")$1;"); + + // newInstance code. + StringBuilder cni = new StringBuilder("protected Object newInstance(").append(GenericObjectInput.class.getName()).append(" in){ return "); + Constructor con = cs[0]; + int mod = con.getModifiers(); + boolean dn = Modifier.isPublic(mod) || ( isp && !Modifier.isPrivate(mod) ); + if( dn ) + { + cni.append("new ").append(cn).append("("); + } + else + { + con.setAccessible(true); + cni.append("constructor.newInstance(new Object[]{"); + } + Class[] pts = con.getParameterTypes(); + for(int i=0;i 0 ) + cni.append(','); + cni.append(defaultArg(pts[i])); + } + if( !dn ) + cni.append("}"); // close object array. + cni.append("); }"); + + // get bean-style property metadata. + Map pms = propertyMetadatas(c); + List> builders = new ArrayList>(fs.length); + String fn, ftn; // field name, field type name. + Class ft; // field type. + boolean da; // direct access. + PropertyMetadata pm; + for(int i=0;i wc = cg.toClass(); + // set static field + wc.getField("fields").set(null, fs); + wc.getField("builders").set(null, builders.toArray(new Builder[0])); + if( !dn ) + wc.getField("constructor").set(null, con); + return (Builder)wc.newInstance(); + } + catch(RuntimeException e) + { + throw e; + } + catch(Throwable e) + { + throw new RuntimeException(e.getMessage(), e); + } + finally + { + cg.release(); + } + } + + private static Builder newEnumBuilder(Class c) + { + ClassLoader cl = ClassHelper.getClassLoader(c); + + String cn = c.getName(); + String bcn = BUILDER_CLASS_NAME + "$bc" + BUILDER_CLASS_COUNTER.getAndIncrement(); + + StringBuilder cwt = new StringBuilder("public void writeTo(Object obj, ").append(GenericObjectOutput.class.getName()).append(" out) throws java.io.IOException{"); // writeTo code. + cwt.append(cn).append(" v = (").append(cn).append(")$1;"); + cwt.append("if( $1 == null ){ $2.writeUTF(null); }else{ $2.writeUTF(v.name()); } }"); + + StringBuilder cpf = new StringBuilder("public Object parseFrom(").append(GenericObjectInput.class.getName()).append(" in) throws java.io.IOException{"); // parseFrom code. + cpf.append("String name = $1.readUTF(); if( name == null ) return null; return (").append(cn).append(")Enum.valueOf(").append(cn).append(".class, name); }"); + + ClassGenerator cg = ClassGenerator.newInstance(cl); + cg.setClassName(bcn); + cg.setSuperClass(Builder.class); + cg.addDefaultConstructor(); + cg.addMethod("public Class getType(){ return " + cn + ".class; }"); + cg.addMethod(cwt.toString()); + cg.addMethod(cpf.toString()); + try + { + Class wc = cg.toClass(); + return (Builder)wc.newInstance(); + } + catch(RuntimeException e) + { + throw e; + } + catch(Throwable e) + { + throw new RuntimeException(e.getMessage(), e); + } + finally + { + cg.release(); + } + } + + private static Map propertyMetadatas(Class c) + { + Map mm = new HashMap(); // method map. + Map ret = new HashMap(); // property metadata map. + + // All public method. + for( Method m : c.getMethods() ) + { + if( m.getDeclaringClass() == Object.class ) // Ignore Object's method. + continue; + mm.put(ReflectUtils.getDesc(m), m); + } + + Matcher matcher; + for( Map.Entry entry : mm.entrySet() ) + { + String desc = entry.getKey(); + Method method = entry.getValue(); + if( ( matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(desc) ).matches() || + ( matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(desc) ).matches() ) + { + String pn = propertyName(matcher.group(1)); + Class pt = method.getReturnType(); + PropertyMetadata pm = ret.get(pn); + if( pm == null ) + { + pm = new PropertyMetadata(); + pm.type = pt; + ret.put(pn, pm); + } + else + { + if( pm.type != pt ) + continue; + } + pm.getter = method.getName(); + } + else if( ( matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(desc) ).matches() ) + { + String pn = propertyName(matcher.group(1)); + Class pt = method.getParameterTypes()[0]; + PropertyMetadata pm = ret.get(pn); + if( pm == null ) + { + pm = new PropertyMetadata(); + pm.type = pt; + ret.put(pn, pm); + } + else + { + if( pm.type != pt ) + continue; + } + pm.setter = method.getName(); + } + } + return ret; + } + + private static String propertyName(String s) + { + return s.length() == 1 || Character.isLowerCase(s.charAt(1)) ? Character.toLowerCase(s.charAt(0)) + s.substring(1) : s; + } + + private static String defaultArg(Class cl) + { + if( !cl.isPrimitive() ) return "null"; + if( boolean.class == cl ) return "false"; + if( int.class == cl ) return "0"; + if( long.class == cl ) return "0l"; + if( double.class == cl ) return "(double)0"; + if( float.class == cl ) return "(float)0"; + if( short.class == cl ) return "(short)0"; + if( char.class == cl ) return "(char)0"; + if( byte.class == cl ) return "(byte)0"; + throw new UnsupportedOperationException(); + } + + private static int compareFieldName(String n1, String n2) + { + int l = Math.min(n1.length(), n2.length()); + for(int i=0;i c) + { + String desc = ReflectUtils.getDesc(c); + int index = mDescList.size(); + mDescList.add(desc); + mDescMap.put(desc, index); + } + + static class PropertyMetadata + { + Class type; + String setter, getter; + } + + public static abstract class AbstractObjectBuilder extends Builder + { + abstract public Class getType(); + + public void writeTo(T obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + int ref = out.getRef(obj); + if( ref < 0 ) + { + out.addRef(obj); + out.write0(OBJECT); + writeObject(obj, out); + } + else + { + out.write0(OBJECT_REF); + out.writeUInt(ref); + } + } + } + + public T parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + switch( b ) + { + case OBJECT: + { + T ret = newInstance(in); + in.addRef(ret); + readObject(ret, in); + return ret; + } + case OBJECT_REF: + return (T)in.getRef(in.readUInt()); + case OBJECT_NULL: + return null; + default: + throw new IOException("Input format error, expect OBJECT|OBJECT_REF|OBJECT_NULL, get " + b); + } + } + + abstract protected void writeObject(T obj, GenericObjectOutput out) throws IOException; + + abstract protected T newInstance(GenericObjectInput in) throws IOException; + + abstract protected void readObject(T ret, GenericObjectInput in) throws IOException; + } + + static final Builder GenericBuilder = new Builder(){ + @Override + public Class getType(){ return Object.class; } + @Override + public void writeTo(Object obj, GenericObjectOutput out) throws IOException{ out.writeObject(obj); } + @Override + public Object parseFrom(GenericObjectInput in) throws IOException{ return in.readObject(); } + }; + + static final Builder GenericArrayBuilder = new AbstractObjectBuilder(){ + @Override + public Class getType(){ return Object[].class; } + @Override + protected Object[] newInstance(GenericObjectInput in) throws IOException + { + return new Object[in.readUInt()]; + } + @Override + protected void readObject(Object[] ret, GenericObjectInput in) throws IOException + { + for(int i=0;i SerializableBuilder = new Builder(){ + @Override + public Class getType() + { + return Serializable.class; + } + @Override + public void writeTo(Serializable obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_STREAM); + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(); + CompactedObjectOutputStream oos = new CompactedObjectOutputStream(bos); + oos.writeObject(obj); + oos.flush(); + bos.close(); + byte[] b = bos.toByteArray(); + out.writeUInt(b.length); + out.write0(b, 0, b.length); + } + } + @Override + public Serializable parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_STREAM ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_STREAM, get " + b + "."); + + UnsafeByteArrayInputStream bis = new UnsafeByteArrayInputStream(in.read0(in.readUInt())); + CompactedObjectInputStream ois = new CompactedObjectInputStream(bis); + try{ return (Serializable)ois.readObject(); } + catch(ClassNotFoundException e){ throw new IOException(StringUtils.toString(e)); } + } + }; + + static + { + addDesc(boolean[].class); + addDesc(byte[].class); + addDesc(char[].class); + addDesc(short[].class); + addDesc(int[].class); + addDesc(long[].class); + addDesc(float[].class); + addDesc(double[].class); + + addDesc(Boolean.class); + addDesc(Byte.class); + addDesc(Character.class); + addDesc(Short.class); + addDesc(Integer.class); + addDesc(Long.class); + addDesc(Float.class); + addDesc(Double.class); + + addDesc(String.class); + addDesc(String[].class); + + addDesc(ArrayList.class); + addDesc(HashMap.class); + addDesc(HashSet.class); + addDesc(Date.class); + addDesc(java.sql.Date.class); + addDesc(java.sql.Time.class); + addDesc(java.sql.Timestamp.class); + addDesc(java.util.LinkedList.class); + addDesc(java.util.LinkedHashMap.class); + addDesc(java.util.LinkedHashSet.class); + + register(byte[].class, new Builder(){ + @Override + public Class getType(){ return byte[].class; } + @Override + public void writeTo(byte[] obj, GenericObjectOutput out) throws IOException{ out.writeBytes(obj); } + @Override + public byte[] parseFrom(GenericObjectInput in) throws IOException{ return in.readBytes(); } + }); + register(Boolean.class, new Builder(){ + @Override + public Class getType(){ return Boolean.class; } + @Override + public void writeTo(Boolean obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + out.write0(VARINT_N1); + else if( obj.booleanValue() ) + out.write0(VARINT_1); + else + out.write0(VARINT_0); + } + @Override + public Boolean parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + switch( b ) + { + case VARINT_N1: return null; + case VARINT_0: return Boolean.FALSE; + case VARINT_1: return Boolean.TRUE; + default: throw new IOException("Input format error, expect VARINT_N1|VARINT_0|VARINT_1, get " + b + "."); + } + } + }); + register(Byte.class, new Builder(){ + @Override + public Class getType(){ return Byte.class; } + @Override + public void writeTo(Byte obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeByte(obj.byteValue()); + } + } + @Override + public Byte parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return Byte.valueOf(in.readByte()); + } + }); + register(Character.class, new Builder(){ + @Override + public Class getType(){ return Character.class; } + @Override + public void writeTo(Character obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeShort((short)obj.charValue()); + } + } + @Override + public Character parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return Character.valueOf((char)in.readShort()); + } + }); + register(Short.class, new Builder(){ + @Override + public Class getType(){ return Short.class; } + @Override + public void writeTo(Short obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeShort(obj.shortValue()); + } + } + @Override + public Short parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return Short.valueOf(in.readShort()); + } + }); + register(Integer.class, new Builder(){ + @Override + public Class getType(){ return Integer.class; } + @Override + public void writeTo(Integer obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeInt(obj.intValue()); + } + } + @Override + public Integer parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return Integer.valueOf(in.readInt()); + } + }); + register(Long.class, new Builder(){ + @Override + public Class getType(){ return Long.class; } + @Override + public void writeTo(Long obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeLong(obj.longValue()); + } + } + @Override + public Long parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return Long.valueOf(in.readLong()); + } + }); + register(Float.class, new Builder(){ + @Override + public Class getType(){ return Float.class; } + @Override + public void writeTo(Float obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeFloat(obj.floatValue()); + } + } + @Override + public Float parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return new Float(in.readFloat()); + } + }); + register(Double.class, new Builder(){ + @Override + public Class getType(){ return Double.class; } + @Override + public void writeTo(Double obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeDouble(obj.doubleValue()); + } + } + @Override + public Double parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return new Double(in.readDouble()); + } + }); + register(String.class, new Builder(){ + @Override + public Class getType(){ return String.class; } + @Override + public String parseFrom(GenericObjectInput in) throws IOException{ return in.readUTF(); } + @Override + public void writeTo(String obj, GenericObjectOutput out) throws IOException{ out.writeUTF(obj); } + }); + register(StringBuilder.class, new Builder(){ + @Override + public Class getType(){ return StringBuilder.class; } + @Override + public StringBuilder parseFrom(GenericObjectInput in) throws IOException{ return new StringBuilder(in.readUTF()); } + @Override + public void writeTo(StringBuilder obj, GenericObjectOutput out) throws IOException{ out.writeUTF(obj.toString()); } + }); + register(StringBuffer.class, new Builder(){ + @Override + public Class getType(){ return StringBuffer.class; } + @Override + public StringBuffer parseFrom(GenericObjectInput in) throws IOException{ return new StringBuffer(in.readUTF()); } + @Override + public void writeTo(StringBuffer obj, GenericObjectOutput out) throws IOException{ out.writeUTF(obj.toString()); } + }); + + // java.util + register(ArrayList.class, new Builder(){ + @Override + public Class getType(){ return ArrayList.class; } + @Override + public void writeTo(ArrayList obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUES); + out.writeUInt(obj.size()); + for( Object item : obj ) + out.writeObject(item); + } + } + @Override + public ArrayList parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUES ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUES, get " + b + "."); + + int len = in.readUInt(); + ArrayList ret = new ArrayList(len); + for(int i=0;i(){ + @Override + public Class getType(){ return HashMap.class; } + @Override + public void writeTo(HashMap obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_MAP); + out.writeUInt(obj.size()); + for( Map.Entry entry : (Set)obj.entrySet() ) + { + out.writeObject(entry.getKey()); + out.writeObject(entry.getValue()); + } + } + } + @Override + public HashMap parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_MAP ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_MAP, get " + b + "."); + + int len = in.readUInt(); + HashMap ret = new HashMap(len); + for(int i=0;i(){ + @Override + public Class getType(){ return HashSet.class; } + @Override + public void writeTo(HashSet obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUES); + out.writeUInt(obj.size()); + for( Object item : obj ) + out.writeObject(item); + } + } + @Override + public HashSet parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUES ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUES, get " + b + "."); + + int len = in.readUInt(); + HashSet ret = new HashSet(len); + for(int i=0;i(){ + @Override + public Class getType(){ return Date.class; } + @Override + public void writeTo(Date obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeLong(obj.getTime()); + } + } + @Override + public Date parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return new Date(in.readLong()); + } + }); + + // java.sql + register(java.sql.Date.class, new Builder(){ + @Override + public Class getType(){ return java.sql.Date.class; } + @Override + public void writeTo(java.sql.Date obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeLong(obj.getTime()); + } + } + @Override + public java.sql.Date parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return new java.sql.Date(in.readLong()); + } + }); + register(java.sql.Timestamp.class, new Builder(){ + @Override + public Class getType(){ return java.sql.Timestamp.class; } + @Override + public void writeTo(java.sql.Timestamp obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeLong(obj.getTime()); + } + } + @Override + public java.sql.Timestamp parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return new java.sql.Timestamp(in.readLong()); + } + }); + register(java.sql.Time.class, new Builder(){ + @Override + public Class getType(){ return java.sql.Time.class; } + @Override + public void writeTo(java.sql.Time obj, GenericObjectOutput out) throws IOException + { + if( obj == null ) + { + out.write0(OBJECT_NULL); + } + else + { + out.write0(OBJECT_VALUE); + out.writeLong(obj.getTime()); + } + } + @Override + public java.sql.Time parseFrom(GenericObjectInput in) throws IOException + { + byte b = in.read0(); + if( b == OBJECT_NULL ) + return null; + if( b != OBJECT_VALUE ) + throw new IOException("Input format error, expect OBJECT_NULL|OBJECT_VALUE, get " + b + "."); + + return new java.sql.Time(in.readLong()); + } + }); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/DubboSerialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/DubboSerialization.java new file mode 100644 index 0000000000..b1111226ee --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/DubboSerialization.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.dubbo; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * @author ding.lid + */ +@Extension("dubbo") +public class DubboSerialization implements Serialization { + + public byte getContentTypeId() { + return 1; + } + + public String getContentType() { + return "x-application/dubbo"; + } + + public ObjectOutput serialize(URL url, OutputStream out) throws IOException { + return new GenericObjectOutput(out); + } + + public ObjectInput deserialize(URL url, InputStream is) throws IOException { + return new GenericObjectInput(is); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataFlags.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataFlags.java new file mode 100644 index 0000000000..efab9600f9 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataFlags.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.dubbo; + +/** + * Constants. + * + * @author qian.lei + */ + +public interface GenericDataFlags +{ + // prefix three bits + byte VARINT = 0, OBJECT = (byte)0x80; + + // varint tag + byte VARINT8 = VARINT, VARINT16 = VARINT | 1, VARINT24 = VARINT | 2, VARINT32 = VARINT | 3; + + byte VARINT40 = VARINT | 4, VARINT48 = VARINT | 5, VARINT56 = VARINT | 6, VARINT64 = VARINT | 7; + + // varint contants + byte VARINT_NF = VARINT | 10, VARINT_NE = VARINT | 11, VARINT_ND = VARINT | 12; + + byte VARINT_NC = VARINT | 13, VARINT_NB = VARINT | 14, VARINT_NA = VARINT | 15, VARINT_N9 = VARINT | 16; + + byte VARINT_N8 = VARINT | 17, VARINT_N7 = VARINT | 18, VARINT_N6 = VARINT | 19, VARINT_N5 = VARINT | 20; + + byte VARINT_N4 = VARINT | 21, VARINT_N3 = VARINT | 22, VARINT_N2 = VARINT | 23, VARINT_N1 = VARINT | 24; + + byte VARINT_0 = VARINT | 25, VARINT_1 = VARINT | 26, VARINT_2 = VARINT | 27, VARINT_3 = VARINT | 28; + + byte VARINT_4 = VARINT | 29, VARINT_5 = VARINT | 30, VARINT_6 = VARINT | 31, VARINT_7 = VARINT | 32; + + byte VARINT_8 = VARINT | 33, VARINT_9 = VARINT | 34, VARINT_A = VARINT | 35, VARINT_B = VARINT | 36; + + byte VARINT_C = VARINT | 37, VARINT_D = VARINT | 38, VARINT_E = VARINT | 39, VARINT_F = VARINT | 40; + + byte VARINT_10 = VARINT | 41, VARINT_11 = VARINT | 42, VARINT_12 = VARINT | 43, VARINT_13 = VARINT | 44; + + byte VARINT_14 = VARINT | 45, VARINT_15 = VARINT | 46, VARINT_16 = VARINT | 47, VARINT_17 = VARINT | 48; + + byte VARINT_18 = VARINT | 49, VARINT_19 = VARINT | 50, VARINT_1A = VARINT | 51, VARINT_1B = VARINT | 52; + + byte VARINT_1C = VARINT | 53, VARINT_1D = VARINT | 54, VARINT_1E = VARINT | 55, VARINT_1F = VARINT | 56; + + // object tag + byte OBJECT_REF = OBJECT | 1, OBJECT_STREAM = OBJECT | 2, OBJECT_BYTES = OBJECT | 3; + + byte OBJECT_VALUE = OBJECT | 4, OBJECT_VALUES = OBJECT | 5, OBJECT_MAP = OBJECT | 6; + + byte OBJECT_DESC = OBJECT | 10, OBJECT_DESC_ID = OBJECT | 11; + + // object constants + byte OBJECT_NULL = OBJECT | 20, OBJECT_DUMMY = OBJECT | 21; +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataInput.java new file mode 100644 index 0000000000..a9dc954f94 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataInput.java @@ -0,0 +1,395 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.dubbo; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UTFDataFormatException; + +import com.alibaba.dubbo.common.serialize.DataInput; + +/** + * Default DataInput impl. + * Not thread-safe. + * + * @author qian.lei + */ + +public class GenericDataInput implements DataInput, GenericDataFlags +{ + private static final String EMPTY_STRING = ""; + + private static final byte[] EMPTY_BYTES = {}; + + private final InputStream mInput; + + private final byte[] mBuffer; + + private int mRead = 0; + + private int mPosition = 0; + + public GenericDataInput(InputStream is) + { + this(is, 1024); + } + + public GenericDataInput(InputStream is, int buffSize) + { + mInput = is; + mBuffer = new byte[buffSize]; + } + + public boolean readBool() throws IOException + { + byte b = read0(); + + switch( b ) + { + case VARINT_0: return false; + case VARINT_1: return true; + default: + throw new IOException("Tag error, expect BYTE_TRUE|BYTE_FALSE, but get " + b); + } + } + + public byte readByte() throws IOException + { + byte b = read0(); + + switch( b ) + { + case VARINT8: + return read0(); + case VARINT_0: return 0; case VARINT_1: return 1; case VARINT_2: return 2; case VARINT_3: return 3; + case VARINT_4: return 4; case VARINT_5: return 5; case VARINT_6: return 6; case VARINT_7: return 7; + case VARINT_8: return 8; case VARINT_9: return 9; case VARINT_A: return 10; case VARINT_B: return 11; + case VARINT_C: return 12; case VARINT_D: return 13; case VARINT_E: return 14; case VARINT_F: return 15; + case VARINT_10: return 16; case VARINT_11: return 17; case VARINT_12: return 18; case VARINT_13: return 19; + case VARINT_14: return 20; case VARINT_15: return 21; case VARINT_16: return 22; case VARINT_17: return 23; + case VARINT_18: return 24; case VARINT_19: return 25; case VARINT_1A: return 26; case VARINT_1B: return 27; + case VARINT_1C: return 28; case VARINT_1D: return 29; case VARINT_1E: return 30; case VARINT_1F: return 31; + default: + throw new IOException("Tag error, expect VARINT, but get " + b); + } + } + + public short readShort() throws IOException + { + return (short)readVarint32(); + } + + public int readInt() throws IOException + { + return readVarint32(); + } + + public long readLong() throws IOException + { + return readVarint64(); + } + + public float readFloat() throws IOException + { + return Float.intBitsToFloat(readVarint32()); + } + + public double readDouble() throws IOException + { + return Double.longBitsToDouble(readVarint64()); + } + + public String readUTF() throws IOException + { + byte b = read0(); + + switch( b ) + { + case OBJECT_BYTES: + int len = readUInt(); + StringBuilder sb = new StringBuilder(); + + for(int i=0;i 0 ) + { + read = mInput.read(ret, pos, len); + if( read == -1 ) + throw new EOFException(); + pos += read; + len -= read; + } + } + return ret; + } + + private int readVarint32() throws IOException + { + byte b = read0(); + + switch( b ) + { + case VARINT8: + return read0(); + case VARINT16: + { + byte b1 = read0(), b2 = read0(); + return (short)( ( b1 & 0xff ) | ( ( b2 & 0xff ) << 8 ) ); + } + case VARINT24: + { + byte b1 = read0(), b2 = read0(), b3 = read0(); + int ret = ( b1 & 0xff ) | ( ( b2 & 0xff ) << 8 ) | ( ( b3 & 0xff ) << 16 ); + if( b3 < 0 ) + return ret | 0xff000000; + return ret; + } + case VARINT32: + { + byte b1 = read0(), b2 = read0(), b3 = read0(), b4 = read0(); + return ( ( b1 & 0xff ) | + ( ( b2 & 0xff ) << 8 ) | + ( ( b3 & 0xff ) << 16 ) | + ( ( b4 & 0xff ) << 24 ) ); + } + case VARINT_NF: return -15; case VARINT_NE: return -14; case VARINT_ND: return -13; + case VARINT_NC: return -12; case VARINT_NB: return -11; case VARINT_NA: return -10; case VARINT_N9: return -9; + case VARINT_N8: return -8; case VARINT_N7: return -7; case VARINT_N6: return -6; case VARINT_N5: return -5; + case VARINT_N4: return -4; case VARINT_N3: return -3; case VARINT_N2: return -2; case VARINT_N1: return -1; + case VARINT_0: return 0; case VARINT_1: return 1; case VARINT_2: return 2; case VARINT_3: return 3; + case VARINT_4: return 4; case VARINT_5: return 5; case VARINT_6: return 6; case VARINT_7: return 7; + case VARINT_8: return 8; case VARINT_9: return 9; case VARINT_A: return 10; case VARINT_B: return 11; + case VARINT_C: return 12; case VARINT_D: return 13; case VARINT_E: return 14; case VARINT_F: return 15; + case VARINT_10: return 16; case VARINT_11: return 17; case VARINT_12: return 18; case VARINT_13: return 19; + case VARINT_14: return 20; case VARINT_15: return 21; case VARINT_16: return 22; case VARINT_17: return 23; + case VARINT_18: return 24; case VARINT_19: return 25; case VARINT_1A: return 26; case VARINT_1B: return 27; + case VARINT_1C: return 28; case VARINT_1D: return 29; case VARINT_1E: return 30; case VARINT_1F: return 31; + default: + throw new IOException("Tag error, expect VARINT, but get " + b); + } + } + + private long readVarint64() throws IOException + { + byte b = read0(); + + switch( b ) + { + case VARINT8: + return read0(); + case VARINT16: + { + byte b1 = read0(), b2 = read0(); + return (short)( ( b1 & 0xff ) | ( ( b2 & 0xff ) << 8 ) ); + } + case VARINT24: + { + byte b1 = read0(), b2 = read0(), b3 = read0(); + int ret = ( b1 & 0xff ) | ( ( b2 & 0xff ) << 8 ) | ( ( b3 & 0xff ) << 16 ); + if( b3 < 0 ) + return ret | 0xff000000; + return ret; + } + case VARINT32: + { + byte b1 = read0(), b2 = read0(), b3 = read0(), b4 = read0(); + return ( ( b1 & 0xff ) | + ( ( b2 & 0xff ) << 8 ) | + ( ( b3 & 0xff ) << 16 ) | + ( ( b4 & 0xff ) << 24 ) ); + } + case VARINT40: + { + byte b1 = read0(), b2 = read0(), b3 = read0(), b4 = read0(), b5 = read0(); + long ret = ( (long)b1 & 0xff ) | + ( ( (long)b2 & 0xff ) << 8 ) | + ( ( (long)b3 & 0xff ) << 16 ) | + ( ( (long)b4 & 0xff ) << 24 ) | + ( ( (long)b5 & 0xff ) << 32 ); + if( b5 < 0 ) + return ret | 0xffffff0000000000l; + return ret; + } + case VARINT48: + { + byte b1 = read0(), b2 = read0(), b3 = read0(), b4 = read0(), b5 = read0(), b6 = read0(); + long ret = ( (long)b1 & 0xff ) | + ( ( (long)b2 & 0xff ) << 8 ) | + ( ( (long)b3 & 0xff ) << 16 ) | + ( ( (long)b4 & 0xff ) << 24 ) | + ( ( (long)b5 & 0xff ) << 32 ) | + ( ( (long)b6 & 0xff ) << 40 ); + if( b6 < 0 ) + return ret | 0xffff000000000000l; + return ret; + } + case VARINT56: + { + byte b1 = read0(), b2 = read0(), b3 = read0(), b4 = read0(), b5 = read0(), b6 = read0(), b7 = read0(); + long ret = ( (long)b1 & 0xff ) | + ( ( (long)b2 & 0xff ) << 8 ) | + ( ( (long)b3 & 0xff ) << 16 ) | + ( ( (long)b4 & 0xff ) << 24 ) | + ( ( (long)b5 & 0xff ) << 32 ) | + ( ( (long)b6 & 0xff ) << 40 ) | + ( ( (long)b7 & 0xff ) << 48 ); + if( b7 < 0 ) + return ret | 0xff00000000000000l; + return ret; + } + case VARINT64: + { + byte b1 = read0(), b2 = read0(), b3 = read0(), b4 = read0(); + byte b5 = read0(), b6 = read0(), b7 = read0(), b8 = read0(); + return ( ( (long)b1 & 0xff ) | + ( ( (long)b2 & 0xff ) << 8 ) | + ( ( (long)b3 & 0xff ) << 16 ) | + ( ( (long)b4 & 0xff ) << 24 ) | + ( ( (long)b5 & 0xff ) << 32 ) | + ( ( (long)b6 & 0xff ) << 40 ) | + ( ( (long)b7 & 0xff ) << 48 ) | + ( ( (long)b8 & 0xff ) << 56 ) ); + } + case VARINT_NF: return -15; case VARINT_NE: return -14; case VARINT_ND: return -13; + case VARINT_NC: return -12; case VARINT_NB: return -11; case VARINT_NA: return -10; case VARINT_N9: return -9; + case VARINT_N8: return -8; case VARINT_N7: return -7; case VARINT_N6: return -6; case VARINT_N5: return -5; + case VARINT_N4: return -4; case VARINT_N3: return -3; case VARINT_N2: return -2; case VARINT_N1: return -1; + case VARINT_0: return 0; case VARINT_1: return 1; case VARINT_2: return 2; case VARINT_3: return 3; + case VARINT_4: return 4; case VARINT_5: return 5; case VARINT_6: return 6; case VARINT_7: return 7; + case VARINT_8: return 8; case VARINT_9: return 9; case VARINT_A: return 10; case VARINT_B: return 11; + case VARINT_C: return 12; case VARINT_D: return 13; case VARINT_E: return 14; case VARINT_F: return 15; + case VARINT_10: return 16; case VARINT_11: return 17; case VARINT_12: return 18; case VARINT_13: return 19; + case VARINT_14: return 20; case VARINT_15: return 21; case VARINT_16: return 22; case VARINT_17: return 23; + case VARINT_18: return 24; case VARINT_19: return 25; case VARINT_1A: return 26; case VARINT_1B: return 27; + case VARINT_1C: return 28; case VARINT_1D: return 29; case VARINT_1E: return 30; case VARINT_1F: return 31; + default: + throw new IOException("Tag error, expect VARINT, but get " + b); + } + } + + private void fillBuffer() throws IOException + { + mPosition = 0; + mRead = mInput.read(mBuffer); + + if( mRead == -1 ) + { + mRead = 0; + throw new EOFException(); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataOutput.java new file mode 100644 index 0000000000..b50ca1f21e --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericDataOutput.java @@ -0,0 +1,344 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.dubbo; + +import java.io.IOException; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.serialize.DataOutput; + +/** + * Default data output impl. + * Not thread-safe. + * + * @author qian.lei + */ + +public class GenericDataOutput implements DataOutput, GenericDataFlags +{ + private static final int CHAR_BUF_SIZE = 256; + + private final byte[] mBuffer, mTemp = new byte[9]; + + private final char[] mCharBuf = new char[CHAR_BUF_SIZE]; + + private final OutputStream mOutput; + + private final int mLimit; + + private int mPosition = 0; + + public GenericDataOutput(OutputStream out) + { + this(out, 1024); + } + + public GenericDataOutput(OutputStream out, int buffSize) + { + mOutput = out; + mLimit = buffSize; + mBuffer = new byte[buffSize]; + } + + public void writeBool(boolean v) throws IOException + { + write0( v ? VARINT_1 : VARINT_0 ); + } + + public void writeByte(byte v) throws IOException + { + switch( v ) + { + case 0: write0(VARINT_0); break; case 1: write0(VARINT_1); break; case 2: write0(VARINT_2); break; case 3: write0(VARINT_3); break; + case 4: write0(VARINT_4); break; case 5: write0(VARINT_5); break; case 6: write0(VARINT_6); break; case 7: write0(VARINT_7); break; + case 8: write0(VARINT_8); break; case 9: write0(VARINT_9); break; case 10: write0(VARINT_A); break; case 11: write0(VARINT_B); break; + case 12: write0(VARINT_C); break; case 13: write0(VARINT_D); break; case 14: write0(VARINT_E); break; case 15: write0(VARINT_F); break; + case 16: write0(VARINT_10); break; case 17: write0(VARINT_11); break; case 18: write0(VARINT_12); break; case 19: write0(VARINT_13); break; + case 20: write0(VARINT_14); break; case 21: write0(VARINT_15); break; case 22: write0(VARINT_16); break; case 23: write0(VARINT_17); break; + case 24: write0(VARINT_18); break; case 25: write0(VARINT_19); break; case 26: write0(VARINT_1A); break; case 27: write0(VARINT_1B); break; + case 28: write0(VARINT_1C); break; case 29: write0(VARINT_1D); break; case 30: write0(VARINT_1E); break; case 31: write0(VARINT_1F); break; + default: + write0(VARINT8); + write0(v); + } + } + + public void writeShort(short v) throws IOException + { + writeVarint32(v); + } + + public void writeInt(int v) throws IOException + { + writeVarint32(v); + } + + public void writeLong(long v) throws IOException + { + writeVarint64(v); + } + + public void writeFloat(float v) throws IOException + { + writeVarint32(Float.floatToRawIntBits(v)); + } + + public void writeDouble(double v) throws IOException + { + writeVarint64(Double.doubleToRawLongBits(v)); + } + + public void writeUTF(String v) throws IOException + { + if( v == null ) + { + write0(OBJECT_NULL); + } + else + { + int len = v.length(); + if( len == 0 ) + { + write0(OBJECT_DUMMY); + } + else + { + write0(OBJECT_BYTES); + writeUInt(len); + + int off = 0, limit = mLimit - 3, size; + char[] buf = mCharBuf; + do + { + size = Math.min(len-off, CHAR_BUF_SIZE); + v.getChars(off, off+size, buf, 0); + + for(int i=0;i limit ) + { + if( c < 0x80 ) + { + write0((byte)c); + } + else if( c < 0x800 ) + { + write0((byte)(0xC0 | ((c >> 6) & 0x1F))); + write0((byte)(0x80 | (c & 0x3F))); + } + else + { + write0((byte)(0xE0 | ((c >> 12) & 0x0F))); + write0((byte)(0x80 | ((c >> 6) & 0x3F))); + write0((byte)(0x80 | (c & 0x3F))); + } + } + else + { + if( c < 0x80 ) + { + mBuffer[mPosition++] = (byte)c; + } + else if( c < 0x800 ) + { + mBuffer[mPosition++] = (byte)(0xC0 | ((c >> 6) & 0x1F)); + mBuffer[mPosition++] = (byte)(0x80 | (c & 0x3F)); + } + else + { + mBuffer[mPosition++] = (byte)(0xE0 | ((c >> 12) & 0x0F)); + mBuffer[mPosition++] = (byte)(0x80 | ((c >> 6) & 0x3F)); + mBuffer[mPosition++] = (byte)(0x80 | (c & 0x3F)); + } + } + } + off += size; + } + while( off < len ); + } + } + } + + public void writeBytes(byte[] b) throws IOException + { + if( b == null ) + write0(OBJECT_NULL); + else + writeBytes(b, 0, b.length); + } + + public void writeBytes(byte[] b, int off, int len) throws IOException + { + if( len == 0 ) + { + write0(OBJECT_DUMMY); + } + else + { + write0(OBJECT_BYTES); + writeUInt(len); + write0(b, off, len); + } + } + + public void flushBuffer() throws IOException + { + if( mPosition > 0 ) + { + mOutput.write(mBuffer, 0, mPosition); + mPosition = 0; + } + } + + public void writeUInt(int v) throws IOException + { + byte tmp; + while( true ) + { + tmp = (byte)( v & 0x7f ); + if( ( v >>>= 7 ) == 0 ) + { + write0( (byte)( tmp | 0x80 ) ); + return; + } + else + { + write0(tmp); + } + } + } + + protected void write0(byte b) throws IOException + { + if( mPosition == mLimit ) + flushBuffer(); + + mBuffer[mPosition++] = b; + } + + protected void write0(byte[] b, int off, int len) throws IOException + { + int rem = mLimit - mPosition; + if( rem > len ) + { + System.arraycopy(b, off, mBuffer, mPosition, len); + mPosition += len; + } + else + { + System.arraycopy(b, off, mBuffer, mPosition, rem); + mPosition = mLimit; + flushBuffer(); + + off += rem; + len -= rem; + + if( mLimit > len ) + { + System.arraycopy(b, off, mBuffer, 0, len); + mPosition = len; + } + else + { + mOutput.write(b, off, len); + } + } + } + + private void writeVarint32(int v) throws IOException + { + switch( v ) + { + case -15: write0(VARINT_NF); break; case -14: write0(VARINT_NE); break; case -13: write0(VARINT_ND); break; + case -12: write0(VARINT_NC); break; case -11: write0(VARINT_NB); break; case -10: write0(VARINT_NA); break; case -9: write0(VARINT_N9); break; + case -8: write0(VARINT_N8); break; case -7: write0(VARINT_N7); break; case -6: write0(VARINT_N6); break; case -5: write0(VARINT_N5); break; + case -4: write0(VARINT_N4); break; case -3: write0(VARINT_N3); break; case -2: write0(VARINT_N2); break; case -1: write0(VARINT_N1); break; + case 0: write0(VARINT_0); break; case 1: write0(VARINT_1); break; case 2: write0(VARINT_2); break; case 3: write0(VARINT_3); break; + case 4: write0(VARINT_4); break; case 5: write0(VARINT_5); break; case 6: write0(VARINT_6); break; case 7: write0(VARINT_7); break; + case 8: write0(VARINT_8); break; case 9: write0(VARINT_9); break; case 10: write0(VARINT_A); break; case 11: write0(VARINT_B); break; + case 12: write0(VARINT_C); break; case 13: write0(VARINT_D); break; case 14: write0(VARINT_E); break; case 15: write0(VARINT_F); break; + case 16: write0(VARINT_10); break; case 17: write0(VARINT_11); break; case 18: write0(VARINT_12); break; case 19: write0(VARINT_13); break; + case 20: write0(VARINT_14); break; case 21: write0(VARINT_15); break; case 22: write0(VARINT_16); break; case 23: write0(VARINT_17); break; + case 24: write0(VARINT_18); break; case 25: write0(VARINT_19); break; case 26: write0(VARINT_1A); break; case 27: write0(VARINT_1B); break; + case 28: write0(VARINT_1C); break; case 29: write0(VARINT_1D); break; case 30: write0(VARINT_1E); break; case 31: write0(VARINT_1F); break; + default: + int t = v, ix = 0; + byte[] b = mTemp; + + while( true ) + { + b[++ix] = (byte)( v & 0xff ); + if( ( v >>>= 8 ) == 0 ) + break; + } + + if( t > 0 ) + { + // [ 0a e2 => 0a e2 00 ] [ 92 => 92 00 ] + if( b[ix] < 0 ) + b[++ix] = 0; + } + else + { + // [ 01 ff ff ff => 01 ff ] [ e0 ff ff ff => e0 ] + while( b[ix] == (byte)0xff && b[ix-1] < 0 ) + ix--; + } + + b[0] = (byte)( VARINT + ix - 1 ); + write0(b, 0, ix+1); + } + } + + private void writeVarint64(long v) throws IOException + { + int i = (int)v; + if( v == i ) + { + writeVarint32(i); + } + else + { + long t = v; + int ix = 0; + byte[] b = mTemp; + + while( true ) + { + b[++ix] = (byte)( v & 0xff ); + if( ( v >>>= 8 ) == 0 ) + break; + } + + if( t > 0 ) + { + // [ 0a e2 => 0a e2 00 ] [ 92 => 92 00 ] + if( b[ix] < 0 ) + b[++ix] = 0; + } + else + { + // [ 01 ff ff ff => 01 ff ] [ e0 ff ff ff => e0 ] + while( b[ix] == (byte)0xff && b[ix-1] < 0 ) + ix--; + } + + b[0] = (byte)( VARINT + ix - 1 ); + write0(b, 0, ix+1); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericObjectInput.java new file mode 100644 index 0000000000..3ec6570830 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/dubbo/GenericObjectInput.java @@ -0,0 +1,236 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.dubbo; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.io.ClassDescriptorMapper; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * Generic Object Input. + * + * @author qian.lei + */ +public class GenericObjectInput extends GenericDataInput implements ObjectInput +{ + private static Object SKIPPED_OBJECT = new Object(); + + private ClassDescriptorMapper mMapper; + + private List mRefs = new ArrayList(); + + public GenericObjectInput(InputStream is) + { + this(is, Builder.DEFAULT_CLASS_DESCRIPTOR_MAPPER); + } + + public GenericObjectInput(InputStream is, ClassDescriptorMapper mapper) + { + super(is); + mMapper = mapper; + } + + public GenericObjectInput(InputStream is, int buffSize) + { + this(is, buffSize, Builder.DEFAULT_CLASS_DESCRIPTOR_MAPPER); + } + + public GenericObjectInput(InputStream is, int buffSize, ClassDescriptorMapper mapper) + { + super(is, buffSize); + mMapper = mapper; + } + + public Object readObject() throws IOException + { + String desc; + byte b = read0(); + + switch( b ) + { + case OBJECT_NULL: + return null; + case OBJECT_DUMMY: + return new Object(); + case OBJECT_DESC: + { + desc = readUTF(); + break; + } + case OBJECT_DESC_ID: + { + int index = readUInt(); + desc = mMapper.getDescriptor(index); + if( desc == null ) + throw new IOException("Can not find desc id: " + index ); + break; + } + default: + throw new IOException("Flag error, expect OBJECT_NULL|OBJECT_DUMMY|OBJECT_DESC|OBJECT_DESC_ID, get " + b); + } + try + { + Class c = ReflectUtils.desc2class(desc); + return Builder.register(c).parseFrom(this); + } + catch(ClassNotFoundException e) + { + throw new IOException("Read object failed, class not found. " + StringUtils.toString(e)); + } + } + + @SuppressWarnings("unchecked") + public T readObject(Class c) throws IOException,ClassNotFoundException + { + return (T)readObject(); + } + + public void addRef(Object obj) + { + mRefs.add(obj); + } + + public Object getRef(int index) throws IOException + { + if( index < 0 || index >= mRefs.size() ) + return null; + + Object ret = mRefs.get(index); + if( ret == SKIPPED_OBJECT ) + throw new IOException("Ref skipped-object."); + return ret; + } + + public void skipAny() throws IOException + { + byte b = read0(); + switch( b ) + { + case VARINT_NF: case VARINT_NE: case VARINT_ND: case VARINT_NC: case VARINT_NB: case VARINT_NA: case VARINT_N9: + case VARINT_N8: case VARINT_N7: case VARINT_N6: case VARINT_N5: case VARINT_N4: case VARINT_N3: case VARINT_N2: case VARINT_N1: + case VARINT_0: case VARINT_1: case VARINT_2: case VARINT_3: case VARINT_4: case VARINT_5: case VARINT_6: case VARINT_7: + case VARINT_8: case VARINT_9: case VARINT_A: case VARINT_B: case VARINT_C: case VARINT_D: case VARINT_E: case VARINT_F: + case VARINT_10: case VARINT_11: case VARINT_12: case VARINT_13: case VARINT_14: case VARINT_15: case VARINT_16: case VARINT_17: + case VARINT_18: case VARINT_19: case VARINT_1A: case VARINT_1B: case VARINT_1C: case VARINT_1D: case VARINT_1E: case VARINT_1F: + case OBJECT_NULL: case OBJECT_DUMMY: + break; + case VARINT8: + { + read0(); + break; + } + case VARINT16: + { + read0(); read0(); + break; + } + case VARINT24: + { + read0(); read0(); read0(); + break; + } + case VARINT32: + { + read0(); read0(); read0(); read0(); + break; + } + case VARINT40: + { + read0(); read0(); read0(); read0(); read0(); + break; + } + case VARINT48: + { + read0(); read0(); read0(); read0(); read0(); read0(); + break; + } + case VARINT56: + { + read0(); read0(); read0(); read0(); read0(); read0(); read0(); + break; + } + case VARINT64: + { + read0(); read0(); read0(); read0(); read0(); read0(); read0(); read0(); + break; + } + case OBJECT: + { + addRef(SKIPPED_OBJECT); + int len = readUInt(); + for(int i=0;i mRefs = new ConcurrentHashMap(); + + private final boolean isAllowNonSerializable; + + public GenericObjectOutput(OutputStream out) + { + this(out, Builder.DEFAULT_CLASS_DESCRIPTOR_MAPPER); + } + + public GenericObjectOutput(OutputStream out, ClassDescriptorMapper mapper) + { + super(out); + mMapper = mapper; + isAllowNonSerializable = false; + } + + public GenericObjectOutput(OutputStream out, int buffSize) + { + this(out, buffSize, Builder.DEFAULT_CLASS_DESCRIPTOR_MAPPER, false); + } + + public GenericObjectOutput(OutputStream out, int buffSize, ClassDescriptorMapper mapper) + { + this(out, buffSize, mapper, false); + } + + public GenericObjectOutput(OutputStream out, int buffSize, ClassDescriptorMapper mapper, boolean isAllowNonSerializable) + { + super(out, buffSize); + mMapper = mapper; + this.isAllowNonSerializable = isAllowNonSerializable; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void writeObject(Object obj) throws IOException + { + if( obj == null ) + { + write0(OBJECT_NULL); + return; + } + + Class c = obj.getClass(); + if( c == Object.class ) + { + write0(OBJECT_DUMMY); + } + else + { + String desc = ReflectUtils.getDesc(c); + int index = mMapper.getDescriptorIndex(desc); + if( index < 0 ) + { + write0(OBJECT_DESC); + writeUTF(desc); + } + else + { + write0(OBJECT_DESC_ID); + writeUInt(index); + } + Builder b = Builder.register(c, isAllowNonSerializable); + b.writeTo(obj, this); + } + } + + public void addRef(Object obj) + { + mRefs.put(obj, mRefs.size()); + } + + public int getRef(Object obj) + { + Integer ref = mRefs.get(obj); + if( ref == null ) + return -1; + return ref.intValue(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2ObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2ObjectInput.java new file mode 100644 index 0000000000..3752306ec4 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2ObjectInput.java @@ -0,0 +1,95 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.hessian; + +import java.io.IOException; +import java.io.InputStream; + +import com.alibaba.com.caucho.hessian.io.Hessian2Input; +import com.alibaba.dubbo.common.serialize.ObjectInput; + +/** + * Hessian2 Object input. + * + * @author qian.lei + */ + +public class Hessian2ObjectInput implements ObjectInput +{ + private final Hessian2Input mH2i; + + public Hessian2ObjectInput(InputStream is) + { + mH2i = new Hessian2Input(is); + mH2i.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY); + } + + public boolean readBool() throws IOException + { + return mH2i.readBoolean(); + } + + public byte readByte() throws IOException + { + return (byte)mH2i.readInt(); + } + + public short readShort() throws IOException + { + return (short)mH2i.readInt(); + } + + public int readInt() throws IOException + { + return mH2i.readInt(); + } + + public long readLong() throws IOException + { + return mH2i.readLong(); + } + + public float readFloat() throws IOException + { + return (float)mH2i.readDouble(); + } + + public double readDouble() throws IOException + { + return mH2i.readDouble(); + } + + public byte[] readBytes() throws IOException + { + return mH2i.readBytes(); + } + + public String readUTF() throws IOException + { + return mH2i.readString(); + } + + public Object readObject() throws IOException + { + return mH2i.readObject(); + } + + @SuppressWarnings("unchecked") + public T readObject(Class cls) throws IOException, + ClassNotFoundException { + return (T) mH2i.readObject(cls); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2ObjectOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2ObjectOutput.java new file mode 100644 index 0000000000..1f3c57d3dd --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2ObjectOutput.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.hessian; + +import java.io.IOException; +import java.io.OutputStream; + +import com.alibaba.com.caucho.hessian.io.Hessian2Output; +import com.alibaba.dubbo.common.serialize.ObjectOutput; + +/** + * Hessian2 Object output. + * + * @author qian.lei + */ + +public class Hessian2ObjectOutput implements ObjectOutput +{ + private final Hessian2Output mH2o; + + public Hessian2ObjectOutput(OutputStream os) + { + mH2o = new Hessian2Output(os); + mH2o.setSerializerFactory(Hessian2SerializerFactory.SERIALIZER_FACTORY); + } + + public void writeBool(boolean v) throws IOException + { + mH2o.writeBoolean(v); + } + + public void writeByte(byte v) throws IOException + { + mH2o.writeInt(v); + } + + public void writeShort(short v) throws IOException + { + mH2o.writeInt(v); + } + + public void writeInt(int v) throws IOException + { + mH2o.writeInt(v); + } + + public void writeLong(long v) throws IOException + { + mH2o.writeLong(v); + } + + public void writeFloat(float v) throws IOException + { + mH2o.writeDouble(v); + } + + public void writeDouble(double v) throws IOException + { + mH2o.writeDouble(v); + } + + public void writeBytes(byte[] b) throws IOException + { + mH2o.writeBytes(b); + } + + public void writeBytes(byte[] b, int off, int len) throws IOException + { + mH2o.writeBytes(b, off, len); + } + + public void writeUTF(String v) throws IOException + { + mH2o.writeString(v); + } + + public void writeObject(Object obj) throws IOException + { + mH2o.writeObject(obj); + } + + public void flushBuffer() throws IOException + { + mH2o.flushBuffer(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2Serialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2Serialization.java new file mode 100644 index 0000000000..1c8431de1b --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2Serialization.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.hessian; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * @author ding.lid + */ +@Extension("hessian2") +public class Hessian2Serialization implements Serialization { + + public static final byte ID = 2; + + public byte getContentTypeId() { + return ID; + } + + public String getContentType() { + return "x-application/hessian2"; + } + + public ObjectOutput serialize(URL url, OutputStream out) throws IOException { + return new Hessian2ObjectOutput(out); + } + + public ObjectInput deserialize(URL url, InputStream is) throws IOException { + return new Hessian2ObjectInput(is); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2SerializerFactory.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2SerializerFactory.java new file mode 100644 index 0000000000..5289be08c8 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/hessian/Hessian2SerializerFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.hessian; + +import com.alibaba.com.caucho.hessian.io.SerializerFactory; + +public class Hessian2SerializerFactory extends SerializerFactory { + + public static final SerializerFactory SERIALIZER_FACTORY = new Hessian2SerializerFactory(); + + private Hessian2SerializerFactory() { + } + + @Override + public ClassLoader getClassLoader() { + return Thread.currentThread().getContextClassLoader(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedJavaSerialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedJavaSerialization.java new file mode 100644 index 0000000000..15353685b1 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedJavaSerialization.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.java; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * @author ding.lid + */ +@Extension("compactedjava") +public class CompactedJavaSerialization implements Serialization { + + public byte getContentTypeId() { + return 4; + } + + public String getContentType() { + return "x-application/compactedjava"; + } + + public ObjectOutput serialize(URL url, OutputStream out) throws IOException { + return new JavaObjectOutput(out, true); + } + + public ObjectInput deserialize(URL url, InputStream is) throws IOException { + return new JavaObjectInput(is, true); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedObjectInputStream.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedObjectInputStream.java new file mode 100644 index 0000000000..34068f6d3a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedObjectInputStream.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.java; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.io.StreamCorruptedException; + +import com.alibaba.dubbo.common.utils.ClassHelper; + +/** + * Compacted java object input stream. + * + * @author qianlei + */ + +public class CompactedObjectInputStream extends ObjectInputStream +{ + private ClassLoader mClassLoader; + + public CompactedObjectInputStream(InputStream in) throws IOException + { + this(in, Thread.currentThread().getContextClassLoader()); + } + + public CompactedObjectInputStream(InputStream in, ClassLoader cl) throws IOException + { + super(in); + mClassLoader = cl == null ? ClassHelper.getClassLoader() : cl; + } + + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException,ClassNotFoundException + { + int type = read(); + if( type < 0 ) + throw new EOFException(); + switch( type ) + { + case 0: + return super.readClassDescriptor(); + case 1: + Class clazz = loadClass(readUTF()); + return ObjectStreamClass.lookup(clazz); + default: + throw new StreamCorruptedException("Unexpected class descriptor type: " + type); + } + } + + private Class loadClass(String className) throws ClassNotFoundException + { + return mClassLoader.loadClass(className); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedObjectOutputStream.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedObjectOutputStream.java new file mode 100644 index 0000000000..716cc21864 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/CompactedObjectOutputStream.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.java; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; + +/** + * Compacted java object output stream. + * + * @author qianlei + */ + +public class CompactedObjectOutputStream extends ObjectOutputStream +{ + public CompactedObjectOutputStream(OutputStream out) throws IOException + { + super(out); + } + + @Override + protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException + { + Class clazz = desc.forClass(); + if( clazz.isPrimitive() || clazz.isArray() ) + { + write(0); + super.writeClassDescriptor(desc); + } + else + { + write(1); + writeUTF(desc.getName()); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaObjectInput.java new file mode 100644 index 0000000000..9b76905219 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaObjectInput.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.java; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; + +import com.alibaba.dubbo.common.serialize.ObjectInput; + +/** + * Java Object input. + * + * @author qian.lei + */ + +public class JavaObjectInput implements ObjectInput +{ + public final static int MAX_BYTE_ARRAY_LENGTH = 8 * 1024 * 1024; + + private final ObjectInputStream mIn; + + public JavaObjectInput(InputStream is) throws IOException + { + mIn = new ObjectInputStream(is); + } + + public JavaObjectInput(InputStream is, boolean compacted) throws IOException + { + mIn = compacted ? new CompactedObjectInputStream(is) : new ObjectInputStream(is); + } + + public boolean readBool() throws IOException + { + return mIn.readBoolean(); + } + + public byte readByte() throws IOException + { + return mIn.readByte(); + } + + public short readShort() throws IOException + { + return mIn.readShort(); + } + + public int readInt() throws IOException + { + return mIn.readInt(); + } + + public long readLong() throws IOException + { + return mIn.readLong(); + } + + public float readFloat() throws IOException + { + return mIn.readFloat(); + } + + public double readDouble() throws IOException + { + return mIn.readDouble(); + } + + public byte[] readBytes() throws IOException + { + int len = mIn.readInt(); + if( len < 0 ) + return null; + if( len == 0 ) + return new byte[0]; + if( len > MAX_BYTE_ARRAY_LENGTH ) + throw new IOException("Byte array length too large. " + len); + + byte[] b = new byte[len]; + mIn.readFully(b); + return b; + } + + public String readUTF() throws IOException + { + int len = mIn.readInt(); + if( len < 0 ) + return null; + + return mIn.readUTF(); + } + + public Object readObject() throws IOException, ClassNotFoundException + { + byte b = mIn.readByte(); + if( b == 0 ) + return null; + + return mIn.readObject(); + } + + @SuppressWarnings("unchecked") + public T readObject(Class cls) throws IOException, + ClassNotFoundException { + return (T) readObject(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaObjectOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaObjectOutput.java new file mode 100644 index 0000000000..f12e031419 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaObjectOutput.java @@ -0,0 +1,123 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.java; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.serialize.ObjectOutput; + +/** + * Java Object output. + * + * @author qian.lei + */ + +public class JavaObjectOutput implements ObjectOutput +{ + private final ObjectOutputStream mOut; + + public JavaObjectOutput(OutputStream os) throws IOException + { + mOut = new ObjectOutputStream(os); + } + + public JavaObjectOutput(OutputStream os, boolean compact) throws IOException + { + mOut = compact ? new CompactedObjectOutputStream(os) : new ObjectOutputStream(os); + } + + public void writeBool(boolean v) throws IOException + { + mOut.writeBoolean(v); + } + + public void writeByte(byte v) throws IOException + { + mOut.writeByte(v); + } + + public void writeShort(short v) throws IOException + { + mOut.writeShort(v); + } + + public void writeInt(int v) throws IOException + { + mOut.writeInt(v); + } + + public void writeLong(long v) throws IOException + { + mOut.writeLong(v); + } + + public void writeFloat(float v) throws IOException + { + mOut.writeFloat(v); + } + + public void writeDouble(double v) throws IOException + { + mOut.writeDouble(v); + } + + public void writeBytes(byte[] b) throws IOException + { + if( b == null ) + mOut.writeInt(-1); + else + this.writeBytes(b, 0, b.length); + } + + public void writeBytes(byte[] b, int off, int len) throws IOException + { + mOut.writeInt(len); + mOut.write(b, off, len); + } + + public void writeUTF(String v) throws IOException + { + if( v == null ) + { + mOut.writeInt(-1); + } + else + { + mOut.writeInt(v.length()); + mOut.writeUTF(v); + } + } + + public void writeObject(Object obj) throws IOException + { + if( obj == null ) + { + mOut.writeByte(0); + } + else + { + mOut.writeByte(1); + mOut.writeObject(obj); + } + } + + public void flushBuffer() throws IOException + { + mOut.flush(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaSerialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaSerialization.java new file mode 100644 index 0000000000..58f1a1cc6a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/java/JavaSerialization.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.java; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * @author ding.lid + */ +@Extension("java") +public class JavaSerialization implements Serialization { + + public byte getContentTypeId() { + return 3; + } + + public String getContentType() { + return "x-application/java"; + } + + public ObjectOutput serialize(URL url, OutputStream out) throws IOException { + return new JavaObjectOutput(out); + } + + public ObjectInput deserialize(URL url, InputStream is) throws IOException { + return new JavaObjectInput(is); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonObjectInput.java new file mode 100644 index 0000000000..79fa7865f9 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonObjectInput.java @@ -0,0 +1,136 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.json; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Map; + +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.fastjson.JSON; + +/** + * JsonObjectInput + * + * @author william.liangf + */ +public class FastJsonObjectInput implements ObjectInput { + + private final BufferedReader reader; + + public FastJsonObjectInput(InputStream in){ + this(new InputStreamReader(in)); + } + + public FastJsonObjectInput(Reader reader){ + this.reader = new BufferedReader(reader); + } + + public boolean readBool() throws IOException { + try { + return readObject(boolean.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public byte readByte() throws IOException { + try { + return readObject( byte.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public short readShort() throws IOException { + try { + return readObject(short.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public int readInt() throws IOException { + try { + return readObject(int.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public long readLong() throws IOException { + try { + return readObject(long.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public float readFloat() throws IOException { + try { + return readObject(float.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public double readDouble() throws IOException { + try { + return readObject(double.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public String readUTF() throws IOException { + try { + return readObject(String.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public byte[] readBytes() throws IOException { + return readLine().getBytes(); + } + + @SuppressWarnings("unchecked") + public Object readObject() throws IOException, ClassNotFoundException { + String json = readLine(); + if (json.startsWith("{")) { + return JSON.parseObject(json, Map.class); + } else { + json = "{\"value\":" + json + "}"; + Map map = JSON.parseObject(json, Map.class); + return map.get("value"); + } + } + + public T readObject(Class cls) throws IOException, ClassNotFoundException { + return JSON.parseObject(readLine(), cls); + } + + private String readLine() throws IOException, EOFException { + String line = reader.readLine(); + if(line == null || line.trim().length() == 0) throw new EOFException(); + return line; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonObjectOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonObjectOutput.java new file mode 100644 index 0000000000..ffaaf97679 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonObjectOutput.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.json; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; + +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.fastjson.serializer.JSONSerializer; +import com.alibaba.fastjson.serializer.SerializeWriter; +import com.alibaba.fastjson.serializer.SerializerFeature; + +/** + * JsonObjectOutput + * + * @author william.liangf + */ +public class FastJsonObjectOutput implements ObjectOutput { + + private final PrintWriter writer; + + public FastJsonObjectOutput(OutputStream out) { + this(new OutputStreamWriter(out)); + } + + public FastJsonObjectOutput(Writer writer) { + this.writer = new PrintWriter(writer); + } + + public void writeBool(boolean v) throws IOException { + writeObject(v); + } + + public void writeByte(byte v) throws IOException { + writeObject(v); + } + + public void writeShort(short v) throws IOException { + writeObject(v); + } + + public void writeInt(int v) throws IOException { + writeObject(v); + } + + public void writeLong(long v) throws IOException { + writeObject(v); + } + + public void writeFloat(float v) throws IOException { + writeObject(v); + } + + public void writeDouble(double v) throws IOException { + writeObject(v); + } + + public void writeUTF(String v) throws IOException { + writeObject(v); + } + + public void writeBytes(byte[] b) throws IOException { + writer.println(new String(b)); + } + + public void writeBytes(byte[] b, int off, int len) throws IOException { + writer.println(new String(b, off, len)); + } + + public void writeObject(Object obj) throws IOException { + SerializeWriter out = new SerializeWriter(); + JSONSerializer serializer = new JSONSerializer(out); + serializer.config(SerializerFeature.WriteEnumUsingToString, true); + serializer.write(obj); + out.writeTo(writer); + writer.println(); + writer.flush(); + } + + public void flushBuffer() throws IOException { + writer.flush(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonSerialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonSerialization.java new file mode 100644 index 0000000000..5e94197273 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/FastJsonSerialization.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.json; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * FastJsonSerialization + * + * @author william.liangf + */ +@Extension("fastjson") +public class FastJsonSerialization implements Serialization { + + public byte getContentTypeId() { + return 6; + } + + public String getContentType() { + return "text/json"; + } + + public ObjectOutput serialize(URL url, OutputStream output) throws IOException { + return new FastJsonObjectOutput(output); + } + + public ObjectInput deserialize(URL url, InputStream input) throws IOException { + return new FastJsonObjectInput(input); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java new file mode 100644 index 0000000000..6fc2154b75 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectInput.java @@ -0,0 +1,146 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.json; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Map; + +import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.dubbo.common.json.ParseException; +import com.alibaba.dubbo.common.serialize.ObjectInput; + +/** + * JsonObjectInput + * + * @author william.liangf + * @author ding.lid + */ +public class JsonObjectInput implements ObjectInput { + + private final BufferedReader reader; + + public JsonObjectInput(InputStream in){ + this(new InputStreamReader(in)); + } + + public JsonObjectInput(Reader reader){ + this.reader = new BufferedReader(reader); + } + + public boolean readBool() throws IOException { + try { + return readObject(boolean.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public byte readByte() throws IOException { + try { + return readObject( byte.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public short readShort() throws IOException { + try { + return readObject(short.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public int readInt() throws IOException { + try { + return readObject(int.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public long readLong() throws IOException { + try { + return readObject(long.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public float readFloat() throws IOException { + try { + return readObject(float.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public double readDouble() throws IOException { + try { + return readObject(double.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public String readUTF() throws IOException { + try { + return readObject(String.class); + } catch (ClassNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + public byte[] readBytes() throws IOException { + return readLine().getBytes(); + } + + public Object readObject() throws IOException, ClassNotFoundException { + try { + String json = readLine(); + if (json.startsWith("{")) { + return JSON.parse(json, Map.class); + } else { + json = "{\"value\":" + json + "}"; + + @SuppressWarnings("unchecked") + Map map = JSON.parse(json, Map.class); + return map.get("value"); + } + } catch (ParseException e) { + throw new IOException(e.getMessage()); + } + } + + public T readObject(Class cls) throws IOException, ClassNotFoundException { + try { + return JSON.parse(readLine(), cls); + } catch (ParseException e) { + throw new IOException(e.getMessage()); + } + } + + private String readLine() throws IOException, EOFException { + String line = reader.readLine(); + if(line == null || line.trim().length() == 0) throw new EOFException(); + return line; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java new file mode 100644 index 0000000000..53ebc2f31e --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonObjectOutput.java @@ -0,0 +1,105 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.json; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; + +import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.dubbo.common.serialize.ObjectOutput; + +/** + * JsonObjectOutput + * + * @author william.liangf + */ +public class JsonObjectOutput implements ObjectOutput { + + private final PrintWriter writer; + + private final boolean writeClass; + + public JsonObjectOutput(OutputStream out) { + this(new OutputStreamWriter(out), false); + } + + public JsonObjectOutput(Writer writer) { + this(writer, false); + } + + public JsonObjectOutput(OutputStream out, boolean writeClass) { + this(new OutputStreamWriter(out), writeClass); + } + + public JsonObjectOutput(Writer writer, boolean writeClass) { + this.writer = new PrintWriter(writer); + this.writeClass = writeClass; + } + + public void writeBool(boolean v) throws IOException { + writeObject(v); + } + + public void writeByte(byte v) throws IOException { + writeObject(v); + } + + public void writeShort(short v) throws IOException { + writeObject(v); + } + + public void writeInt(int v) throws IOException { + writeObject(v); + } + + public void writeLong(long v) throws IOException { + writeObject(v); + } + + public void writeFloat(float v) throws IOException { + writeObject(v); + } + + public void writeDouble(double v) throws IOException { + writeObject(v); + } + + public void writeUTF(String v) throws IOException { + writeObject(v); + } + + public void writeBytes(byte[] b) throws IOException { + writer.println(new String(b)); + } + + public void writeBytes(byte[] b, int off, int len) throws IOException { + writer.println(new String(b, off, len)); + } + + public void writeObject(Object obj) throws IOException { + JSON.json(obj, writer, writeClass); + writer.println(); + writer.flush(); + } + + public void flushBuffer() throws IOException { + writer.flush(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java new file mode 100644 index 0000000000..cd3c99c24d --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/serialize/support/json/JsonSerialization.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.support.json; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * JsonSerialization + * + * @author william.liangf + */ +@Extension("json") +public class JsonSerialization implements Serialization { + + public byte getContentTypeId() { + return 5; + } + + public String getContentType() { + return "text/json"; + } + + public ObjectOutput serialize(URL url, OutputStream output) throws IOException { + return new JsonObjectOutput(output, url.getBooleanParameter("with.class", true)); + } + + public ObjectInput deserialize(URL url, InputStream input) throws IOException { + return new JsonObjectInput(input); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/Status.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/Status.java new file mode 100644 index 0000000000..a4472f9ca1 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/Status.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.status; + +/** + * Status + * + * @author william.liangf + */ +public class Status { + + /** + * Level + */ + public static enum Level { + OK, WARN, ERROR, UNKNOWN + } + + private final Level level; + + private final String message; + + public Status(Level level){ + this(level, null); + } + + /** + * + * @param level + * @param message + */ + public Status(Level level, String message){ + this.level = level; + this.message = message; + } + + public Level getLevel() { + return level; + } + + public String getMessage() { + return message; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/StatusChecker.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/StatusChecker.java new file mode 100644 index 0000000000..c97bad621c --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/StatusChecker.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.status; + +import com.alibaba.dubbo.common.Extension; + +/** + * StatusChecker + * + * @author william.liangf + */ +@Extension +public interface StatusChecker { + + /** + * check status + * + * @return status + */ + Status check(); + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/LoadStatusChecker.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/LoadStatusChecker.java new file mode 100644 index 0000000000..dc08083ea7 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/LoadStatusChecker.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.status.support; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; + +/** + * Load Status + * + * @author william.liangf + */ +@Extension("load") +public class LoadStatusChecker implements StatusChecker { + + public Status check() { + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + double load; + try { + Method method = OperatingSystemMXBean.class.getMethod("getSystemLoadAverage", new Class[0]); + load = (Double)method.invoke(operatingSystemMXBean, new Object[0]); + } catch (Throwable e) { + load = -1; + } + int cpu = operatingSystemMXBean.getAvailableProcessors(); + return new Status(load < 0 ? Status.Level.UNKNOWN : (load < cpu ? Status.Level.OK : Status.Level.WARN), (load < 0 ? "" : "load:" + load + ",") + "cpu:" + cpu); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/MemoryStatusChecker.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/MemoryStatusChecker.java new file mode 100644 index 0000000000..947b2104bb --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/MemoryStatusChecker.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.status.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; + +/** + * MemoryStatus + * + * @author william.liangf + */ +@Extension("memory") +public class MemoryStatusChecker implements StatusChecker { + + public Status check() { + Runtime runtime = Runtime.getRuntime(); + long freeMemory = runtime.freeMemory(); + long totalMemory = runtime.totalMemory(); + long maxMemory = runtime.maxMemory(); + boolean ok = (maxMemory - (totalMemory - freeMemory) > 2048); // 剩余空间小于2M报警 + String msg = "max:" + (maxMemory / 1024 / 1024) + "M,total:" + + (totalMemory / 1024 / 1024) + "M,used:" + ((totalMemory / 1024 / 1024) - (freeMemory / 1024 / 1024)) + "M"; + return new Status(ok ? Status.Level.OK : Status.Level.WARN, msg); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/StatusUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/StatusUtils.java new file mode 100644 index 0000000000..f909499e78 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/status/support/StatusUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.status.support; + +import java.util.Map; + +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.Status.Level; + +/** + * StatusManager + * + * @author william.liangf + */ +public class StatusUtils { + + public static Status getSummaryStatus(Map statuses) { + Level level = Level.OK; + StringBuilder msg = new StringBuilder(); + for (Map.Entry entry : statuses.entrySet()) { + String key = entry.getKey(); + Status status = entry.getValue(); + Level l = status.getLevel(); + if (Level.ERROR.equals(l)) { + level = Level.ERROR; + if (msg.length() > 0) { + msg.append(","); + } + msg.append(key); + } else if (Level.WARN.equals(l)) { + if(! Level.ERROR.equals(level)) { + level = Level.WARN; + } + if (msg.length() > 0) { + msg.append(","); + } + msg.append(key); + } + } + return new Status(level, msg.toString()); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/ThreadPool.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/ThreadPool.java new file mode 100644 index 0000000000..4223644c0a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/ThreadPool.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.threadpool; + +import java.util.concurrent.Executor; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * ThreadPool + * + * @author william.liangf + */ +@Extension("fixed") +public interface ThreadPool { + + /** + * 线程池 + * + * @param url + * @return + */ + @Adaptive({Constants.THREADPOOL_KEY}) + Executor getExecutor(URL url); + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java new file mode 100644 index 0000000000..4296e5e331 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/AbortPolicyWithReport.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.threadpool.support; + +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +/** + * Abort Policy. + * Log warn info when abort. + * + * @author ding.lid + */ +public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy { + + protected static final Logger logger = LoggerFactory.getLogger(AbortPolicyWithReport.class); + + private final String threadName; + + private final URL url; + + public AbortPolicyWithReport(String threadName, URL url) { + this.threadName = threadName; + this.url = url; + } + + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + String msg = String.format("Thread pool is EXHAUSTED!" + + " Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d), Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s!" , + threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(), + e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(), url.toIdentityString()); + logger.warn(msg); + throw new RejectedExecutionException(msg); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/cached/CachedThreadPool.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/cached/CachedThreadPool.java new file mode 100644 index 0000000000..1facff2242 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/cached/CachedThreadPool.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.threadpool.support.cached; + +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.threadpool.ThreadPool; +import com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; + +/** + * CachedThreadPool + * + * @see java.util.concurrent.Executors#newCachedThreadPool() + * @author william.liangf + */ +@Extension("cached") +public class CachedThreadPool implements ThreadPool { + + public Executor getExecutor(URL url) { + String threadName = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME); + int threads = url.getIntParameter(Constants.THREADS_KEY, Integer.MAX_VALUE); + int queues = url.getIntParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES); + int keepalive = url.getIntParameter(Constants.THREAD_ALIVE_KEY, Constants.DEFAULT_THREAD_ALIVE); + return new ThreadPoolExecutor(0, threads, keepalive, TimeUnit.MILLISECONDS, + queues <= 0 ? new SynchronousQueue() : new LinkedBlockingQueue(queues), + new NamedThreadFactory(threadName, true), new AbortPolicyWithReport(threadName, url)); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/fixed/FixedThreadPool.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/fixed/FixedThreadPool.java new file mode 100644 index 0000000000..fe2020d612 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/threadpool/support/fixed/FixedThreadPool.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.threadpool.support.fixed; + +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.threadpool.ThreadPool; +import com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; + +/** + * FixedThreadPool + * + * @see java.util.concurrent.Executors#newFixedThreadPool(int) + * @author william.liangf + */ +@Extension("fixed") +public class FixedThreadPool implements ThreadPool { + + public Executor getExecutor(URL url) { + String threadName = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME); + int threads = url.getIntParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); + int queues = url.getIntParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES); + return new ThreadPoolExecutor(threads, threads, Constants.DEFAULT_THREAD_ALIVE, TimeUnit.MILLISECONDS, + queues <= 0 ? new SynchronousQueue() : new LinkedBlockingQueue(queues), + new NamedThreadFactory(threadName, true), new AbortPolicyWithReport(threadName, url)); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/AtomicPositiveInteger.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/AtomicPositiveInteger.java new file mode 100644 index 0000000000..b1ade56c5c --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/AtomicPositiveInteger.java @@ -0,0 +1,186 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * AtomicPositiveInteger + * + * @author william.liangf + * @author ding.lid + */ +public class AtomicPositiveInteger extends Number { + + private static final long serialVersionUID = -3038533876489105940L; + + private final AtomicInteger i; + + public AtomicPositiveInteger() { + i = new AtomicInteger(); + } + + public AtomicPositiveInteger(int initialValue) { + i = new AtomicInteger(initialValue); + } + + public final int getAndIncrement() { + for (;;) { + int current = i.get(); + int next = (current >= Integer.MAX_VALUE ? 0 : current + 1); + if (i.compareAndSet(current, next)) { + return current; + } + } + } + + public final int getAndDecrement() { + for (;;) { + int current = i.get(); + int next = (current <= 0 ? Integer.MAX_VALUE : current - 1); + if (i.compareAndSet(current, next)) { + return current; + } + } + } + + public final int incrementAndGet() { + for (;;) { + int current = i.get(); + int next = (current >= Integer.MAX_VALUE ? 0 : current + 1); + if (i.compareAndSet(current, next)) { + return next; + } + } + } + + public final int decrementAndGet() { + for (;;) { + int current = i.get(); + int next = (current <= 0 ? Integer.MAX_VALUE : current - 1); + if (i.compareAndSet(current, next)) { + return next; + } + } + } + + public final int get() { + return i.get(); + } + + public final void set(int newValue) { + if (newValue < 0) { + throw new IllegalArgumentException("new value " + newValue + " < 0"); + } + i.set(newValue); + } + + public final int getAndSet(int newValue) { + if (newValue < 0) { + throw new IllegalArgumentException("new value " + newValue + " < 0"); + } + return i.getAndSet(newValue); + } + + public final int getAndAdd(int delta) { + if (delta < 0) { + throw new IllegalArgumentException("delta " + delta + " < 0"); + } + for (;;) { + int current = i.get(); + int next = (current >= Integer.MAX_VALUE - delta + 1 ? delta - 1 : current + delta); + if (i.compareAndSet(current, next)) { + return current; + } + } + } + + public final int addAndGet(int delta) { + if (delta < 0) { + throw new IllegalArgumentException("delta " + delta + " < 0"); + } + for (;;) { + int current = i.get(); + int next = (current >= Integer.MAX_VALUE - delta + 1 ? delta - 1 : current + delta); + if (i.compareAndSet(current, next)) { + return next; + } + } + } + + public final boolean compareAndSet(int expect, int update) { + if (update < 0) { + throw new IllegalArgumentException("update value " + update + " < 0"); + } + return i.compareAndSet(expect, update); + } + + public final boolean weakCompareAndSet(int expect, int update) { + if (update < 0) { + throw new IllegalArgumentException("update value " + update + " < 0"); + } + return i.weakCompareAndSet(expect, update); + } + + public byte byteValue() { + return i.byteValue(); + } + + public short shortValue() { + return i.shortValue(); + } + + public int intValue() { + return i.intValue(); + } + + public long longValue() { + return i.longValue(); + } + + public float floatValue() { + return i.floatValue(); + } + + public double doubleValue() { + return i.doubleValue(); + } + + public String toString() { + return i.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((i == null) ? 0 : i.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + AtomicPositiveInteger other = (AtomicPositiveInteger) obj; + if (i == null) { + if (other.i != null) return false; + } else if (!i.equals(other.i)) return false; + return true; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ClassHelper.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ClassHelper.java new file mode 100644 index 0000000000..0c66eddb97 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ClassHelper.java @@ -0,0 +1,191 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class ClassHelper { + + /** + * get class loader + * + * @param cls + * @return class loader + */ + public static ClassLoader getClassLoader(Class cls) { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (Throwable ex) { + // Cannot access thread context ClassLoader - falling back to system class loader... + } + if (cl == null) { + // No thread context class loader -> use class loader of this class. + cl = cls.getClassLoader(); + } + return cl; + } + + /** + * Return the default ClassLoader to use: typically the thread context + * ClassLoader, if available; the ClassLoader that loaded the ClassUtils + * class will be used as fallback. + *

    + * Call this method if you intend to use the thread context ClassLoader in a + * scenario where you absolutely need a non-null ClassLoader reference: for + * example, for class path resource loading (but not necessarily for + * Class.forName, which accepts a null ClassLoader + * reference as well). + * + * @return the default ClassLoader (never null) + * @see java.lang.Thread#getContextClassLoader() + */ + public static ClassLoader getClassLoader() { + return getClassLoader(ClassHelper.class); + } + + /** + * Same as Class.forName(), except that it works for primitive + * types. + */ + public static Class forName(String name) throws ClassNotFoundException { + return forName(name, getClassLoader()); + } + + /** + * Replacement for Class.forName() that also returns Class + * instances for primitives (like "int") and array class names (like + * "String[]"). + * + * @param name the name of the Class + * @param classLoader the class loader to use (may be null, + * which indicates the default class loader) + * @return Class instance for the supplied name + * @throws ClassNotFoundException if the class was not found + * @throws LinkageError if the class file could not be loaded + * @see Class#forName(String, boolean, ClassLoader) + */ + public static Class forName(String name, ClassLoader classLoader) + throws ClassNotFoundException, LinkageError { + + Class clazz = resolvePrimitiveClassName(name); + if (clazz != null) { + return clazz; + } + + // "java.lang.String[]" style arrays + if (name.endsWith(ARRAY_SUFFIX)) { + String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length()); + Class elementClass = forName(elementClassName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + // "[Ljava.lang.String;" style arrays + int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX); + if (internalArrayMarker != -1 && name.endsWith(";")) { + String elementClassName = null; + if (internalArrayMarker == 0) { + elementClassName = name + .substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1); + } else if (name.startsWith("[")) { + elementClassName = name.substring(1); + } + Class elementClass = forName(elementClassName, classLoader); + return Array.newInstance(elementClass, 0).getClass(); + } + + ClassLoader classLoaderToUse = classLoader; + if (classLoaderToUse == null) { + classLoaderToUse = getClassLoader(); + } + return classLoaderToUse.loadClass(name); + } + + /** + * Resolve the given class name as primitive class, if appropriate, + * according to the JVM's naming rules for primitive classes. + *

    + * Also supports the JVM's internal class names for primitive arrays. Does + * not support the "[]" suffix notation for primitive arrays; this is + * only supported by {@link #forName}. + * + * @param name the name of the potentially primitive class + * @return the primitive class, or null if the name does not + * denote a primitive class or primitive array class + */ + public static Class resolvePrimitiveClassName(String name) { + Class result = null; + // Most class names will be quite long, considering that they + // SHOULD sit in a package, so a length check is worthwhile. + if (name != null && name.length() <= 8) { + // Could be a primitive - likely. + result = (Class) primitiveTypeNameMap.get(name); + } + return result; + } + + /** Suffix for array class names: "[]" */ + public static final String ARRAY_SUFFIX = "[]"; + /** Prefix for internal array class names: "[L" */ + private static final String INTERNAL_ARRAY_PREFIX = "[L"; + + /** + * Map with primitive type name as key and corresponding primitive type as + * value, for example: "int" -> "int.class". + */ + private static final Map> primitiveTypeNameMap = new HashMap>(16); + + /** + * Map with primitive wrapper type as key and corresponding primitive type + * as value, for example: Integer.class -> int.class. + */ + private static final Map,Class> primitiveWrapperTypeMap = new HashMap, Class>(8); + + static { + primitiveWrapperTypeMap.put(Boolean.class, boolean.class); + primitiveWrapperTypeMap.put(Byte.class, byte.class); + primitiveWrapperTypeMap.put(Character.class, char.class); + primitiveWrapperTypeMap.put(Double.class, double.class); + primitiveWrapperTypeMap.put(Float.class, float.class); + primitiveWrapperTypeMap.put(Integer.class, int.class); + primitiveWrapperTypeMap.put(Long.class, long.class); + primitiveWrapperTypeMap.put(Short.class, short.class); + + Set> primitiveTypeNames = new HashSet>(16); + primitiveTypeNames.addAll(primitiveWrapperTypeMap.values()); + primitiveTypeNames.addAll(Arrays + .asList(new Class[] { boolean[].class, byte[].class, char[].class, double[].class, + float[].class, int[].class, long[].class, short[].class })); + for (Iterator> it = primitiveTypeNames.iterator(); it.hasNext();) { + Class primitiveClass = (Class) it.next(); + primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass); + } + } + + public static String toShortString(Object obj){ + if(obj == null){ + return "null"; + } + return obj.getClass().getSimpleName() + "@" + System.identityHashCode(obj); + + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/CollectionUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/CollectionUtils.java new file mode 100644 index 0000000000..d3f9234de0 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/CollectionUtils.java @@ -0,0 +1,188 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CollectionUtils { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static List sort(List list) { + if (list != null && list.size() > 0) { + Collections.sort((List)list); + } + return list; + } + + private static final Comparator SIMPLE_NAME_COMPARATOR = new Comparator() { + public int compare(String s1, String s2) { + if (s1 == null && s2 == null) { + return 0; + } + if (s1 == null) { + return -1; + } + if (s2 == null) { + return 1; + } + int i1 = s1.lastIndexOf('.'); + if (i1 >= 0) { + s1 = s1.substring(i1 + 1); + } + int i2 = s2.lastIndexOf('.'); + if (i2 >= 0) { + s2 = s2.substring(i2 + 1); + } + return s1.compareToIgnoreCase(s2); + } + }; + + public static List sortSimpleName(List list) { + if (list != null && list.size() > 0) { + Collections.sort(list, SIMPLE_NAME_COMPARATOR); + } + return list; + } + + public static Map> splitAll(Map> list, String separator) { + if (list == null) { + return null; + } + Map> result = new HashMap>(); + for (Map.Entry> entry : list.entrySet()) { + result.put(entry.getKey(), split(entry.getValue(), separator)); + } + return result; + } + + public static Map> joinAll(Map> map, String separator) { + if (map == null) { + return null; + } + Map> result = new HashMap>(); + for (Map.Entry> entry : map.entrySet()) { + result.put(entry.getKey(), join(entry.getValue(), separator)); + } + return result; + } + + public static Map split(List list, String separator) { + if (list == null) { + return null; + } + Map map = new HashMap(); + if (list == null || list.size() == 0) { + return map; + } + for (String item : list) { + int index = item.indexOf(separator); + if (index == -1) { + map.put(item, ""); + } else { + map.put(item.substring(0, index), item.substring(index + 1)); + } + } + return map; + } + + public static List join(Map map, String separator) { + if (map == null) { + return null; + } + List list = new ArrayList(); + if (map == null || map.size() == 0) { + return list; + } + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (value == null || value.length() == 0) { + list.add(key); + } else { + list.add(key + separator + value); + } + } + return list; + } + + public static boolean mapEquals(Map map1, Map map2) { + if (map1 == null && map2 == null) { + return true; + } + if (map1 == null || map2 == null) { + return false; + } + if (map1.size() != map2.size()) { + return false; + } + for (Map.Entry entry : map1.entrySet()) { + Object key = entry.getKey(); + Object value1 = entry.getValue(); + Object value2 = map2.get(key); + if (! objectEquals(value1, value2)) { + return false; + } + } + return true; + } + + private static boolean objectEquals(Object obj1, Object obj2) { + if (obj1 == null && obj2 == null) { + return true; + } + if (obj1 == null || obj2 == null) { + return false; + } + return obj1.equals(obj2); + } + + public static Map toStringMap(String... pairs) { + Map parameters = new HashMap(); + if (pairs.length > 0) { + if (pairs.length % 2 != 0) { + throw new IllegalArgumentException("pairs must be even."); + } + for (int i = 0; i < pairs.length; i = i + 2) { + parameters.put(pairs[i], pairs[i + 1]); + } + } + return parameters; + } + + @SuppressWarnings("unchecked") + public static Map toMap(Object ... pairs) { + Map ret = new HashMap(); + if (pairs == null || pairs.length == 0) return ret; + + if (pairs.length % 2 != 0) { + throw new IllegalArgumentException("Map pairs can not be odd number."); + } + int len = pairs.length / 2; + for (int i = 0; i < len; i ++) { + ret.put((K) pairs[2 * i], (V) pairs[2 * i + 1]); + } + return ret; + } + + private CollectionUtils() { + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/CompatibleTypeUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/CompatibleTypeUtils.java new file mode 100644 index 0000000000..173b468948 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/CompatibleTypeUtils.java @@ -0,0 +1,173 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * @author ding.lid + */ +public class CompatibleTypeUtils { + private CompatibleTypeUtils() { + } + + private static final List> INETGER_LIKE_TYPES; + private static final List> FLOAT_LIKE_TYPES; + static { + List> list = new ArrayList>(); + list.add(byte.class); + list.add(Byte.class); + list.add(short.class); + list.add(Short.class); + list.add(int.class); + list.add(Integer.class); + list.add(long.class); + list.add(Long.class); + + INETGER_LIKE_TYPES = Collections.unmodifiableList(list); + + list = new ArrayList>(); + list.add(float.class); + list.add(Float.class); + list.add(double.class); + list.add(Double.class); + + FLOAT_LIKE_TYPES = Collections.unmodifiableList(list); + }; + + public static boolean isIntegerLikeType(Class clazz) { + return INETGER_LIKE_TYPES.contains(clazz); + } + + public static boolean isFloatLikeType(Class clazz) { + return FLOAT_LIKE_TYPES.contains(clazz); + } + + public static Object convertIntegerLikeType(Object value, Class clazz) { + if(value == null || clazz == null || value.getClass().equals(clazz)) return value; + + Class valueClass = value.getClass(); + if (!INETGER_LIKE_TYPES.contains(valueClass)) { + String msg = String.format("Input value(type: %s) is not a integer like type!", valueClass); + throw new IllegalArgumentException(msg); + } + if (!INETGER_LIKE_TYPES.contains(clazz)) { + String msg = String.format("Destination type(%s) is not a integer like type!", clazz); + throw new IllegalArgumentException(msg); + } + + Number n = (Number) value; + if (clazz.equals(INETGER_LIKE_TYPES.get(0)) + || clazz.equals(INETGER_LIKE_TYPES.get(1))) { + if(n.longValue() > Byte.MAX_VALUE || n.longValue() < Byte.MIN_VALUE ) { + throw new IllegalStateException("Overflow/Underflow when convert value to compatible type byte!"); + } + return n.byteValue(); + } else if (clazz.equals(INETGER_LIKE_TYPES.get(2)) + || clazz.equals(INETGER_LIKE_TYPES.get(3))) { + if(n.longValue() > Short.MAX_VALUE || n.longValue() < Short.MIN_VALUE ) { + throw new IllegalStateException("Overflow/Underflow when convert value to compatible type short!"); + } + return n.shortValue(); + } else if (clazz.equals(INETGER_LIKE_TYPES.get(4)) + || clazz.equals(INETGER_LIKE_TYPES.get(5))) { + if(n.longValue() > Integer.MAX_VALUE || n.longValue() < Integer.MIN_VALUE ) { + throw new IllegalStateException("Overflow/Underflow when convert value to compatible type int!"); + } + return n.intValue(); + } + return n.longValue(); + } + + public static Object convertFloatLikeType(Object value, Class clazz) { + if(value ==null || clazz == null || value.getClass().equals(clazz)) return value; + + Class valueClass = value.getClass(); + if (!FLOAT_LIKE_TYPES.contains(valueClass)) { + String msg = String.format("Input value(type: %s) is not a float like type!", valueClass); + throw new IllegalArgumentException(msg); + } + if (!FLOAT_LIKE_TYPES.contains(clazz)) { + String msg = String.format("Destination type(%s) is not a float like type!", clazz); + throw new IllegalArgumentException(msg); + } + + Number n = (Number) value; + if (clazz.equals(FLOAT_LIKE_TYPES.get(0)) + || clazz.equals(FLOAT_LIKE_TYPES.get(1))) { + return n.floatValue(); + } + + return n.doubleValue(); + } + + public static boolean needCompatibleTypeConvert(Object value, Class destinationType) { + return value != null && destinationType != null && ! value.getClass().equals(destinationType); + } + + public static boolean isCharType(Class clazz) { + return char.class.equals(clazz) || Character.class.equals(clazz); + } + + public static Character covert2Char(String value) { + String s = (String) value; + if(s.length() != 1) { + String msg = String.format("CAN NOT convert String(%s) to char!" + + " when convert String to char, the String MUST only 1 char.", s); + throw new IllegalArgumentException(msg); + } + return s.charAt(0); + } + + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + /** + * 兼容类型转换。null值是OK的。如果不需要转换,则返回原来的值。 + * 进行的兼容类型转换如下:(基本类对应的Wrapper类型不再列出。) + *

      + *
    • String -> char, enum, Date + *
    • byte, short, int, long -> byte, short, int, long + *
    • float, double -> float, double + *
    + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Object compatibleTypeConvert(Object value, Class destinationType) { + if(! needCompatibleTypeConvert(value, destinationType)) { + return value; + } + if (isCharType(destinationType) && value instanceof String) { + return CompatibleTypeUtils.covert2Char((String) value); + } else if(destinationType.isEnum() && value instanceof String) { + return Enum.valueOf((Class)destinationType, (String) value); + } else if(destinationType == Date.class && value instanceof String) { + try { + return new SimpleDateFormat(DATE_FORMAT).parse((String) value); + } catch (ParseException e) { + throw new IllegalStateException("Failed to parse date " + value + " by format " + DATE_FORMAT + ", cause: " + e.getMessage(), e); + } + } else if(CompatibleTypeUtils.isIntegerLikeType(destinationType)) { + return CompatibleTypeUtils.convertIntegerLikeType(value, destinationType); + } else if(CompatibleTypeUtils.isFloatLikeType(destinationType)) { + return CompatibleTypeUtils.convertFloatLikeType(value, destinationType); + } + return value; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConcurrentHashSet.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConcurrentHashSet.java new file mode 100644 index 0000000000..7714efcb0d --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConcurrentHashSet.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.AbstractSet; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class ConcurrentHashSet extends AbstractSet implements Set, java.io.Serializable { + + private static final long serialVersionUID = -8672117787651310382L; + + private static final Object PRESENT = new Object(); + + private final ConcurrentHashMap map; + + public ConcurrentHashSet(){ + map = new ConcurrentHashMap(); + } + + public ConcurrentHashSet(int initialCapacity){ + map = new ConcurrentHashMap(initialCapacity); + } + + /** + * Returns an iterator over the elements in this set. The elements are + * returned in no particular order. + * + * @return an Iterator over the elements in this set + * @see ConcurrentModificationException + */ + public Iterator iterator() { + return map.keySet().iterator(); + } + + /** + * Returns the number of elements in this set (its cardinality). + * + * @return the number of elements in this set (its cardinality) + */ + public int size() { + return map.size(); + } + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Returns true if this set contains the specified element. More + * formally, returns true if and only if this set contains an + * element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o + * element whose presence in this set is to be tested + * @return true if this set contains the specified element + */ + public boolean contains(Object o) { + return map.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. More + * formally, adds the specified element e to this set if this set + * contains no element e2 such that + * (e==null ? e2==null : e.equals(e2)). If this + * set already contains the element, the call leaves the set unchanged and + * returns false. + * + * @param e + * element to be added to this set + * @return true if this set did not already contain the specified + * element + */ + public boolean add(E e) { + return map.put(e, PRESENT) == null; + } + + /** + * Removes the specified element from this set if it is present. More + * formally, removes an element e such that + * (o==null ? e==null : o.equals(e)), if this + * set contains such an element. Returns true if this set contained + * the element (or equivalently, if this set changed as a result of the + * call). (This set will not contain the element once the call returns.) + * + * @param o + * object to be removed from this set, if present + * @return true if the set contained the specified element + */ + public boolean remove(Object o) { + return map.remove(o) == PRESENT; + } + + /** + * Removes all of the elements from this set. The set will be empty after + * this call returns. + */ + public void clear() { + map.clear(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java new file mode 100644 index 0000000000..8e689d41e6 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ConfigUtils.java @@ -0,0 +1,80 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; + +public class ConfigUtils { + + public static boolean isNotEmpty(String value) { + return ! isEmpty(value); + } + + public static boolean isEmpty(String value) { + return value == null || value.length() == 0 + || "null".equalsIgnoreCase(value) + || "false".equalsIgnoreCase(value) + || "N/A".equalsIgnoreCase(value); + } + + public static boolean isDefault(String value) { + return "true".equalsIgnoreCase(value) + || "default".equalsIgnoreCase(value); + } + + public static List mergeValues(Class type, String cfg, List def) { + List defaults = new ArrayList(); + if (def != null) { + for (String name : def) { + if (ExtensionLoader.getExtensionLoader(type).hasExtension(name)) { + defaults.add(name); + } + } + } + List names = new ArrayList(); + String[] configs = cfg == null ? new String[0] : Constants.COMMA_SPLIT_PATTERN.split(cfg); + for (String config : configs) { + if(config != null && config.length() > 0) { + String[] fs = Constants.COMMA_SPLIT_PATTERN.split(config); + names.addAll(Arrays.asList(fs)); + } + } + if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { + int i = names.indexOf(Constants.DEFAULT_KEY); + if (i > 0) { + names.addAll(i, defaults); + } else { + names.addAll(defaults); + } + names.remove(Constants.DEFAULT_KEY); + } + for (String name : new ArrayList(names)) { + if (name.startsWith(Constants.REMOVE_VALUE_PREFIX)) { + names.remove(name); + names.remove(name.substring(1)); + } + } + return names; + } + + private ConfigUtils() {} + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java new file mode 100644 index 0000000000..f997f8f163 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/DubboAppender.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.spi.LoggingEvent; + +public class DubboAppender extends ConsoleAppender { + + public static boolean available = false; + + public static List logList = new ArrayList(); + + public static void doStart() { + available = true; + } + + public static void doStop() { + available = false; + } + + public void append(LoggingEvent event) { + super.append(event); + if (available == true) { + Log temp = parseLog(event); + logList.add(temp); + } + } + + private Log parseLog(LoggingEvent event) { + Log log = new Log(); + log.setLogName(event.getLogger().getName()); + log.setLogLevel(event.getLevel()); + log.setLogThread(event.getThreadName()); + log.setLogMessage(event.getMessage().toString()); + return log; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java new file mode 100644 index 0000000000..b6110f8fae --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ExecutorUtil.java @@ -0,0 +1,110 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +/** + * @author chao.liuc + * + */ +public class ExecutorUtil { + private static final Logger logger = LoggerFactory.getLogger(ExecutorUtil.class); + private static final ThreadPoolExecutor shutdownExecutor = new ThreadPoolExecutor(0, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(100), + new NamedThreadFactory("Close-ExecutorService-Timer", true)); + + public static boolean isShutdown(Executor executor) { + if (executor instanceof ExecutorService) { + if (((ExecutorService) executor).isShutdown()) { + return true; + } + } + return false; + } + public static void gracefulShutdown(Executor executor, int timeout) { + if (!(executor instanceof ExecutorService) || isShutdown(executor)) { + return; + } + final ExecutorService es = (ExecutorService) executor; + try { + es.shutdown(); // Disable new tasks from being submitted + } catch (SecurityException ex2) { + return ; + } catch (NullPointerException ex2) { + return ; + } + try { + if(! es.awaitTermination(timeout, TimeUnit.MILLISECONDS)) { + es.shutdownNow(); + } + } catch (InterruptedException ex) { + es.shutdownNow(); + Thread.currentThread().interrupt(); + } + if (!isShutdown(es)){ + newThreadToCloseExecutor(es ,timeout); + } + } + public static void shutdownNow(Executor executor, final int timeout) { + if (!(executor instanceof ExecutorService) || isShutdown(executor)) { + return; + } + final ExecutorService es = (ExecutorService) executor; + try { + es.shutdownNow(); + } catch (SecurityException ex2) { + return ; + } catch (NullPointerException ex2) { + return ; + } + try { + es.awaitTermination(timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + if (!isShutdown(es)){ + newThreadToCloseExecutor(es ,timeout); + } + } + + private static void newThreadToCloseExecutor(final ExecutorService es, final int timeout) { + if (!isShutdown(es)) { + shutdownExecutor.execute(new Runnable() { + public void run() { + try { + es.shutdownNow(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + try { + es.awaitTermination(timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + }); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/IOUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/IOUtils.java new file mode 100644 index 0000000000..d83fcc798e --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/IOUtils.java @@ -0,0 +1,235 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +public class IOUtils +{ + private static final int BUFFER_SIZE = 1024 * 8; + + private IOUtils() {} + + /** + * write. + * + * @param is InputStream instance. + * @param os OutputStream instance. + * @return count. + * @throws IOException. + */ + public static long write(InputStream is, OutputStream os) throws IOException + { + return write(is, os, BUFFER_SIZE); + } + + /** + * write. + * + * @param is InputStream instance. + * @param os OutputStream instance. + * @param bufferSize buffer size. + * @return count. + * @throws IOException. + */ + public static long write(InputStream is, OutputStream os, int bufferSize) throws IOException + { + int read; + long total = 0; + byte[] buff = new byte[bufferSize]; + while( is.available() > 0 ) + { + read = is.read(buff, 0, buff.length); + if( read > 0 ) + { + os.write(buff, 0, read); + total += read; + } + } + return total; + } + + /** + * read string. + * + * @param reader Reader instance. + * @return String. + * @throws IOException. + */ + public static String read(Reader reader) throws IOException + { + StringWriter writer = new StringWriter(); + try + { + write(reader, writer); + return writer.getBuffer().toString(); + } + finally{ writer.close(); } + } + + /** + * write string. + * + * @param writer Writer instance. + * @param string String. + * @throws IOException. + */ + public static long write(Writer writer, String string) throws IOException + { + Reader reader = new StringReader(string); + try{ return write(reader, writer); }finally{ reader.close(); } + } + + /** + * write. + * + * @param reader Reader. + * @param writer Writer. + * @return count. + * @throws IOException. + */ + public static long write(Reader reader, Writer writer) throws IOException + { + return write(reader, writer, BUFFER_SIZE); + } + + /** + * write. + * + * @param reader Reader. + * @param writer Writer. + * @param bufferSize buffer size. + * @return count. + * @throws IOException. + */ + public static long write(Reader reader, Writer writer, int bufferSize) throws IOException + { + int read; + long total = 0; + char[] buf = new char[BUFFER_SIZE]; + while( ( read = reader.read(buf) ) != -1 ) + { + writer.write(buf, 0, read); + total += read; + } + return total; + } + + /** + * read lines. + * + * @param file file. + * @return lines. + * @throws IOException. + */ + public static String[] readLines(File file) throws IOException + { + if( file == null || !file.exists() || !file.canRead() ) + return new String[0]; + + return readLines(new FileInputStream(file)); + } + + /** + * read lines. + * + * @param file file. + * @return lines. + * @throws IOException. + */ + public static String[] readLines(InputStream is) throws IOException + { + List lines = new ArrayList(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + try + { + String line; + while( (line = reader.readLine()) != null ) + lines.add(line); + return lines.toArray(new String[0]); + } + finally + { + reader.close(); + } + } + + /** + * write lines. + * + * @param file file. + * @param lines lines. + * @throws IOException. + */ + public static void writeLines(OutputStream os, String[] lines) throws IOException + { + PrintWriter writer = new PrintWriter(new OutputStreamWriter(os)); + try + { + for( String line : lines ) + writer.println(line); + writer.flush(); + } + finally + { + writer.close(); + } + } + + /** + * write lines. + * + * @param file file. + * @param lines lines. + * @throws IOException. + */ + public static void writeLines(File file, String[] lines) throws IOException + { + if( file == null ) + throw new IOException("File is null."); + writeLines(new FileOutputStream(file), lines); + } + + /** + * append lines. + * + * @param file file. + * @param lines lines. + * @throws IOException. + */ + public static void appendLines(File file, String[] lines) throws IOException + { + if( file == null ) + throw new IOException("File is null."); + writeLines(new FileOutputStream(file, true), lines); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/LRUCache.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/LRUCache.java new file mode 100644 index 0000000000..71853c9031 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/LRUCache.java @@ -0,0 +1,116 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.LinkedHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class LRUCache extends LinkedHashMap { + + private static final long serialVersionUID = -5167631809472116969L; + + private static final float DEFAULT_LOAD_FACTOR = 0.75f; + + private static final int DEFAULT_MAX_CAPACITY = 1000; + + private volatile int maxCapacity; + + private final Lock lock = new ReentrantLock(); + + public LRUCache() { + this(DEFAULT_MAX_CAPACITY); + } + + public LRUCache(int maxCapacity) { + super(16, DEFAULT_LOAD_FACTOR, true); + this.maxCapacity = maxCapacity; + } + + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + return size() > maxCapacity; + } + + @Override + public boolean containsKey(Object key) { + try { + lock.lock(); + return super.containsKey(key); + } finally { + lock.unlock(); + } + } + + @Override + public V get(Object key) { + try { + lock.lock(); + return super.get(key); + } finally { + lock.unlock(); + } + } + + @Override + public V put(K key, V value) { + try { + lock.lock(); + return super.put(key, value); + } finally { + lock.unlock(); + } + } + + @Override + public V remove(Object key) { + try { + lock.lock(); + return super.remove(key); + } finally { + lock.unlock(); + } + } + + @Override + public int size() { + try { + lock.lock(); + return super.size(); + } finally { + lock.unlock(); + } + } + + @Override + public void clear() { + try { + lock.lock(); + super.clear(); + } finally { + lock.unlock(); + } + } + + public int getMaxCapacity() { + return maxCapacity; + } + + public void setMaxCapacity(int maxCapacity) { + this.maxCapacity = maxCapacity; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Log.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Log.java new file mode 100644 index 0000000000..477b6ce9f4 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Log.java @@ -0,0 +1,102 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.io.Serializable; + +import org.apache.log4j.Level; + +/** + * Log.java + * + * @author tony.chenl + */ +public class Log implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -534113138054377073L; + private String logName; + private Level logLevel; + private String logMessage; + private String logThread; + + public String getLogName() { + return logName; + } + + public void setLogName(String logName) { + this.logName = logName; + } + + public Level getLogLevel() { + return logLevel; + } + + public void setLogLevel(Level logLevel) { + this.logLevel = logLevel; + } + + public String getLogMessage() { + return logMessage; + } + + public void setLogMessage(String logMessage) { + this.logMessage = logMessage; + } + + public String getLogThread() { + return logThread; + } + + public void setLogThread(String logThread) { + this.logThread = logThread; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((logLevel == null) ? 0 : logLevel.hashCode()); + result = prime * result + ((logMessage == null) ? 0 : logMessage.hashCode()); + result = prime * result + ((logName == null) ? 0 : logName.hashCode()); + result = prime * result + ((logThread == null) ? 0 : logThread.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Log other = (Log) obj; + if (logLevel == null) { + if (other.logLevel != null) return false; + } else if (!logLevel.equals(other.logLevel)) return false; + if (logMessage == null) { + if (other.logMessage != null) return false; + } else if (!logMessage.equals(other.logMessage)) return false; + if (logName == null) { + if (other.logName != null) return false; + } else if (!logName.equals(other.logName)) return false; + if (logThread == null) { + if (other.logThread != null) return false; + } else if (!logThread.equals(other.logThread)) return false; + return true; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/LogUtil.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/LogUtil.java new file mode 100644 index 0000000000..83f065fb26 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/LogUtil.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Level; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +/** + * TODO Comment of LogTest + * + * @author tony.chenl + */ +public class LogUtil { + + private static Logger Log = LoggerFactory.getLogger(LogUtil.class); + + public static void start() { + DubboAppender.doStart(); + } + + public static void stop() { + DubboAppender.doStop(); + } + + public static boolean checkNoError() { + if (findLevel(Level.ERROR) == 0) { + return true; + } else { + return false; + } + + } + + public static int findName(String expectedLogName) { + int count = 0; + List logList = DubboAppender.logList; + for (int i = 0; i < logList.size(); i++) { + String logName = logList.get(i).getLogName(); + if (logName.contains(expectedLogName)) count++; + } + return count; + } + + public static int findLevel(Level expectedLevel) { + int count = 0; + List logList = DubboAppender.logList; + for (int i = 0; i < logList.size(); i++) { + Level logLevel = logList.get(i).getLogLevel(); + if (logLevel.equals(expectedLevel)) count++; + } + return count; + } + + public static int findThread(String expectedThread) { + int count = 0; + List logList = DubboAppender.logList; + for (int i = 0; i < logList.size(); i++) { + String logThread = logList.get(i).getLogThread(); + if (logThread.contains(expectedThread)) count++; + } + return count; + } + + public static int findMessage(String expectedMessage) { + int count = 0; + List logList = DubboAppender.logList; + for (int i = 0; i < logList.size(); i++) { + String logMessage = logList.get(i).getLogMessage(); + if (logMessage.contains(expectedMessage)) count++; + } + return count; + } + + public static void printList(List list) { + Log.info("PrintList:"); + Iterator it = list.iterator(); + while (it.hasNext()) { + Log.info(it.next().toString()); + } + + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NamedThreadFactory.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NamedThreadFactory.java new file mode 100755 index 0000000000..b9da491d56 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NamedThreadFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * InternalThreadFactory. + * + * @author qian.lei + */ + +public class NamedThreadFactory implements ThreadFactory +{ + private static final AtomicInteger POOL_SEQ = new AtomicInteger(1); + + private final AtomicInteger mThreadNum = new AtomicInteger(1); + + private final String mPrefix; + + private final boolean mDaemo; + + private final ThreadGroup mGroup; + + public NamedThreadFactory() + { + this("pool-" + POOL_SEQ.getAndIncrement(),false); + } + + public NamedThreadFactory(String prefix) + { + this(prefix,false); + } + + public NamedThreadFactory(String prefix,boolean daemo) + { + mPrefix = prefix + "-thread-"; + mDaemo = daemo; + SecurityManager s = System.getSecurityManager(); + mGroup = ( s == null ) ? Thread.currentThread().getThreadGroup() : s.getThreadGroup(); + } + + public Thread newThread(Runnable runnable) + { + String name = mPrefix + mThreadNum.getAndIncrement(); + Thread ret = new Thread(mGroup,runnable,name,0); + ret.setDaemon(mDaemo); + return ret; + } + + public ThreadGroup getThreadGroup() + { + return mGroup; + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NetUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NetUtils.java new file mode 100644 index 0000000000..3ceecf511a --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NetUtils.java @@ -0,0 +1,237 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.util.Enumeration; +import java.util.Map; +import java.util.Random; +import java.util.regex.Pattern; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +/** + * IP and Port Helper for RPC, + * + * @author shawn.qianx + */ + +public class NetUtils { + + private static final Logger logger = LoggerFactory.getLogger(NetUtils.class); + + public static final String LOCALHOST = "127.0.0.1"; + + public static final String ANYHOST = "0.0.0.0"; + + private static final int RND_PORT_START = 30000; + + private static final int RND_PORT_RANGE = 10000; + + private static final Random RANDOM = new Random(System.currentTimeMillis()); + + public static int getRandomPort() { + return RND_PORT_START + RANDOM.nextInt(RND_PORT_RANGE); + } + + public static int getAvailablePort() { + ServerSocket ss = null; + try { + ss = new ServerSocket(); + ss.bind(null); + return ss.getLocalPort(); + } catch (IOException e) { + return getRandomPort(); + } finally { + if (ss != null) { + try { + ss.close(); + } catch (IOException e) { + } + } + } + } + + private static final int MIN_PORT = 0; + + private static final int MAX_PORT = 65535; + + public static boolean isInvalidPort(int port){ + return port > MIN_PORT || port <= MAX_PORT; + } + + private static final Pattern ADDRESS_PATTERN = Pattern.compile("^\\d{1,3}(\\.\\d{1,3}){3}\\:\\d{1,5}$"); + + public static boolean isValidAddress(String address){ + return ADDRESS_PATTERN.matcher(address).matches(); + } + + private static final Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$"); + public static boolean isInvalidLocalHost(String host) { + return host == null + || host.length() == 0 + || host.equalsIgnoreCase("localhost") + || host.equals("0.0.0.0") + || (LOCAL_IP_PATTERN.matcher(host).matches()); + } + + public static boolean isValidLocalHost(String host) { + return ! isInvalidLocalHost(host); + } + + public static InetSocketAddress getLocalSocketAddress(String host, int port) { + return isInvalidLocalHost(host) ? + new InetSocketAddress(port) : new InetSocketAddress(host, port); + } + + private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$"); + + private static boolean isValidAddress(InetAddress address) { + if (address == null || address.isLoopbackAddress()) + return false; + String name = address.getHostAddress(); + return (name != null + && ! ANYHOST.equals(name) + && ! LOCALHOST.equals(name) + && IP_PATTERN.matcher(name).matches()); + } + + public static String getLocalHost(){ + InetAddress address = getLocalAddress(); + return address == null ? null : address.getHostAddress(); + } + + public static String filterLocalHost(String host) { + if (NetUtils.isInvalidLocalHost(host)) { + return NetUtils.getLocalHost(); + } + return host; + } + + private static volatile InetAddress LOCAL_ADDRESS = null; + + /** + * 遍历本地网卡,返回第一个合理的IP。 + * + * @return 本地网卡IP + */ + public static InetAddress getLocalAddress() { + if (LOCAL_ADDRESS != null) + return LOCAL_ADDRESS; + InetAddress localAddress = getLocalAddress0(); + LOCAL_ADDRESS = localAddress; + return localAddress; + } + + private static InetAddress getLocalAddress0() { + InetAddress localAddress = null; + try { + localAddress = InetAddress.getLocalHost(); + if (isValidAddress(localAddress)) { + return localAddress; + } + } catch (Throwable e) { + logger.warn("Failed to retriving ip address, " + e.getMessage(), e); + } + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (interfaces != null) { + while (interfaces.hasMoreElements()) { + try { + NetworkInterface network = interfaces.nextElement(); + Enumeration addresses = network.getInetAddresses(); + if (addresses != null) { + while (addresses.hasMoreElements()) { + try { + InetAddress address = addresses.nextElement(); + if (isValidAddress(address)) { + return address; + } + } catch (Throwable e) { + logger.warn("Failed to retriving ip address, " + e.getMessage(), e); + } + } + } + } catch (Throwable e) { + logger.warn("Failed to retriving ip address, " + e.getMessage(), e); + } + } + } + } catch (Throwable e) { + logger.warn("Failed to retriving ip address, " + e.getMessage(), e); + } + logger.error("Could not get local host ip address, will use 127.0.0.1 instead."); + return localAddress; + } + + private static final Map hostNameCache = new LRUCache(1000); + + public static String getHostName(String address) { + try { + int i = address.indexOf(':'); + if (i > -1) { + address = address.substring(0, i); + } + String hostname = hostNameCache.get(address); + if (hostname != null && hostname.length() > 0) { + return hostname; + } + InetAddress inetAddress = InetAddress.getByName(address); + if (inetAddress != null) { + hostname = inetAddress.getHostName(); + hostNameCache.put(address, hostname); + return hostname; + } + } catch (Throwable e) { + // ignore + } + return address; + } + + public static String toAddressString(InetSocketAddress address) { + return address.getAddress().getHostAddress() + ":" + address.getPort(); + } + + public static InetSocketAddress toAddress(String address) { + int i = address.indexOf(':'); + String host; + int port; + if (i > -1) { + host = address.substring(0, i); + port = Integer.parseInt(address.substring(i + 1)); + } else { + host = address; + port = 0; + } + return new InetSocketAddress(host, port); + } + + public static String toURL(String protocol, String host, int port, String path) { + StringBuilder sb = new StringBuilder(); + sb.append(protocol).append("://"); + sb.append(host).append(':').append(port); + if( path.charAt(0) != '/' ) + sb.append('/'); + sb.append(path); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java new file mode 100644 index 0000000000..1996afdf86 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/PojoUtils.java @@ -0,0 +1,451 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +/** + * PojoUtils. Travel object deeply, and convert complex type to simple type. + *

    + * Type below will be remained: + *

      + *
    • Primitive Type, also include String, Number(Integer, Long), Date + *
    • Array of Primitive Type + *
    • Collection, eg: List, Map, Set etc. + *
    + *

    + * Other type will be covert to a map which contains the attributes and value pair of object. + * + * @author william.liangf + * @author ding.lid + */ +public class PojoUtils { + + public static Object[] generalize(Object[] objs) { + Object[] dests = new Object[objs.length]; + for (int i = 0; i < objs.length; i ++) { + dests[i] = generalize(objs[i]); + } + return dests; + } + + public static Object[] realize(Object[] objs, Class[] types) { + if (objs.length != types.length) + throw new IllegalArgumentException("args.length != types.length"); + Object[] dests = new Object[objs.length]; + for (int i = 0; i < objs.length; i ++) { + dests[i] = realize(objs[i], types[i]); + } + return dests; + } + + public static Object generalize(Object pojo) { + return generalize(pojo, new HashMap()); + } + + @SuppressWarnings("unchecked") + private static Object generalize(Object pojo, Map history) { + if (pojo == null) { + return null; + } + + if (pojo instanceof Enum) { + return ((Enum)pojo).name(); + } + if (pojo.getClass().isArray() + && Enum.class.isAssignableFrom( + pojo.getClass().getComponentType())) { + int len = Array.getLength(pojo); + String[] values = new String[len]; + for (int i = 0; i < len; i ++) { + values[i] = ((Enum)Array.get(pojo, i)).name(); + } + return values; + } + + if (isBase(pojo.getClass())) { + return pojo; + } + + Integer id = System.identityHashCode(pojo); + if (history.containsKey(id)) { + return history.get(id); + } + history.put(id, pojo); + + if (pojo.getClass().isArray()) { + int len = Array.getLength(pojo); + Object[] dest = new Object[len]; + for (int i = 0; i < len; i ++) { + Object obj = Array.get(pojo, i); + dest[i] = generalize(obj, history); + } + return dest; + } + if (pojo instanceof Collection) { + Collection src = (Collection)pojo; + int len = src.size(); + Collection dest = (pojo instanceof List) ? new ArrayList(len) : new HashSet(len); + for (Object obj : src) { + dest.add(generalize(obj, history)); + } + return dest; + } + if (pojo instanceof Map) { + Map src = (Map)pojo; + Map tmp = new HashMap(src.size()); + tmp.putAll(src); + for (Map.Entry obj : tmp.entrySet()) { + src.put(generalize(obj.getKey(), history), generalize(obj.getValue(), history)); + } + return src; + } + Map map = new HashMap(); + history.put(id, map); + map.put("class", pojo.getClass().getName()); + for (Method method : pojo.getClass().getMethods()) { + if (Modifier.isPublic(method.getModifiers()) + && method.getDeclaringClass() != Object.class + && method.getParameterTypes().length == 0) { + String name = method.getName(); + try { + if (name.startsWith("get")) { + map.put(name.substring(3, 4).toLowerCase() + name.substring(4), generalize(method + .invoke(pojo, new Object[0]), history)); + } else if (name.startsWith("is")) { + map.put(name.substring(2, 3).toLowerCase() + name.substring(3), generalize(method + .invoke(pojo, new Object[0]), history)); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + return map; + } + + public static Object realize(Object pojo, Class type) { + return realize(pojo, type, new HashMap()); + } + + public static Object realize(Object pojo, Class type, Type genericType) { + return realize(pojo, type, genericType, new HashMap()); + } + + private static class PojoInvocationHandler implements InvocationHandler { + + private Map map; + + public PojoInvocationHandler(Map map) { + this.map = map; + } + + @SuppressWarnings("unchecked") + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getDeclaringClass() == Object.class) { + return method.invoke(map, args); + } + String methodName = method.getName(); + Object value = null; + if (methodName.length() > 3 && methodName.startsWith("get")) { + value = map.get(methodName.substring(3, 4).toLowerCase() + methodName.substring(4)); + } else if (methodName.length() > 2 && methodName.startsWith("is")) { + value = map.get(methodName.substring(2, 3).toLowerCase() + methodName.substring(3)); + } else { + value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1)); + } + if (value instanceof Map && ! Map.class.isAssignableFrom(method.getReturnType())) { + value = realize((Map)value, method.getReturnType(), new HashMap()); + } + return value; + } + } + + @SuppressWarnings("unchecked") + private static Collection createCollection(Class type, int len) { + if (type.isAssignableFrom(ArrayList.class)) { + return new ArrayList(len); + } + if (type.isAssignableFrom(HashSet.class)) { + return new HashSet(len); + } + if (! type.isInterface() && ! Modifier.isAbstract(type.getModifiers())) { + try { + return (Collection) type.newInstance(); + } catch (Exception e) { + // ignore + } + } + return new ArrayList(); + } + + private static Object realize(Object pojo, Class type, final Map history) { + return realize(pojo, type, null , history); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static Object realize(Object pojo, Class type, Type genericType, final Map history) { + if (pojo == null) { + return null; + } + + if (type != null && type.isEnum() + && pojo.getClass() == String.class) { + return Enum.valueOf((Class)type, (String)pojo); + } + + if (isBase(pojo.getClass()) + && ! (type != null && type.isArray() + && type.getComponentType().isEnum() + && pojo.getClass() == String[].class)) { + return CompatibleTypeUtils.compatibleTypeConvert(pojo, type); + } + + Integer id = System.identityHashCode(pojo); + if (history.containsKey(id)) { + return history.get(id); + } + history.put(id, pojo); + + if (pojo.getClass().isArray()) { + if (Collection.class.isAssignableFrom(type)) { + Class ctype = pojo.getClass().getComponentType(); + int len = Array.getLength(pojo); + Collection dest = createCollection(type, len); + for (int i = 0; i < len; i ++) { + Object obj = Array.get(pojo, i); + Object value = realize(obj, ctype, history); + dest.add(value); + } + return dest; + } else { + Class ctype = (type != null && type.isArray() ? type.getComponentType() : pojo.getClass().getComponentType()); + int len = Array.getLength(pojo); + Object dest = Array.newInstance(ctype, len); + for (int i = 0; i < len; i ++) { + Object obj = Array.get(pojo, i); + Object value = realize(obj, ctype, history); + Array.set(dest, i, value); + } + return dest; + } + } + + if (pojo instanceof Collection) { + if (type.isArray()) { + Class ctype = type.getComponentType(); + Collection src = (Collection)pojo; + int len = src.size(); + Object dest = Array.newInstance(ctype, len); + int i = 0; + for (Object obj : src) { + Object value = realize(obj, ctype, history); + Array.set(dest, i, value); + i ++; + } + return dest; + } else { + Collection src = (Collection)pojo; + int len = src.size(); + Collection dest = createCollection(type, len); + for (Object obj : src) { + Type keyType = getGenericClassByIndex(genericType, 0); + Class keyClazz = obj.getClass() ; + if ( keyType instanceof Class){ + keyClazz = (Class)keyType; + } + Object value = realize(obj, keyClazz, keyType, history); + dest.add(value); + } + return dest; + } + } + + if (pojo instanceof Map && type != null) { + Object className = ((Map)pojo).get("class"); + if (className instanceof String && ! Map.class.isAssignableFrom(type)) { + try { + type = ClassHelper.forName((String)className); + } catch (ClassNotFoundException e) { + // ignore + } + } + Map map ; + // 返回值类型不是方法签名类型的子集 并且 不是接口类型 + if (! type.isInterface() + && ! type.isAssignableFrom(pojo.getClass())){ + try { + map = (Map)type.newInstance(); + } catch (Exception e) { + //ignore error + map = (Map)pojo; + } + }else { + map = (Map)pojo; + } + + if (Map.class.isAssignableFrom(type) || type == Object.class) { + final Map tmp = new HashMap(map.size()); + tmp.putAll(map); + for (Map.Entry entry : tmp.entrySet()) { + Type keyType = getGenericClassByIndex(genericType, 0); + Type valueType = getGenericClassByIndex(genericType, 1); + Class keyClazz = entry.getKey().getClass(); + if ( keyType instanceof Class){ + keyClazz = (Class)keyType; + } + Class valueClazz = entry.getValue().getClass() ; + if ( valueType instanceof Class){ + valueClazz = (Class)valueType; + } + + Object key = realize(entry.getKey(), keyClazz, keyType, history); + Object value = realize(entry.getValue(), valueClazz, valueType, history); + map.put(key, value); + } + return map; + } else if (type.isInterface()) { + Object dest = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{type}, new PojoInvocationHandler(map)); + history.put(id, dest); + return dest; + } else { + Object dest = newInstance(type); + history.put(id, dest); + for (Map.Entry entry : map.entrySet()) { + Object key = entry.getKey(); + if (key instanceof String) { + String name = (String) key; + Object value = entry.getValue(); + if (value != null) { + Method method = getSetterMethod(dest.getClass(), name, value.getClass()); + if (method != null) { + if (! method.isAccessible()) + method.setAccessible(true); + value = realize(value, method.getParameterTypes()[0], history); + try { + method.invoke(dest, value); + } catch (Exception e) { + throw new RuntimeException("Failed to set pojo " + dest.getClass().getSimpleName() + " property " + name + " value " + value + ", cause: " + e.getMessage(), e); + } + } + } + } + } + return dest; + } + } + return pojo; + } + + /** + * 获取范型的类型 + * @param genericType + * @param index + * @return List 返回Person.class ,Map index=0 返回String.class index=1 返回Person.class + */ + private static Type getGenericClassByIndex(Type genericType, int index){ + Type clazz = null ; + //范型参数转换 + if (genericType instanceof ParameterizedType){ + ParameterizedType t = (ParameterizedType)genericType; + Type[] types = t.getActualTypeArguments(); + clazz = types[index]; + } + return clazz; + } + + private static Object newInstance(Class cls) { + try { + return cls.newInstance(); + } catch (Throwable t) { + try { + Constructor[] constructors = cls.getConstructors(); + if (constructors != null && constructors.length > 0) { + throw new RuntimeException("Illegal constructor: " + cls.getName()); + } + Constructor constructor = constructors[0]; + if (constructor.getParameterTypes().length > 0) { + for (Constructor c : constructors) { + if (c.getParameterTypes().length < + constructor.getParameterTypes().length) { + constructor = c; + if (constructor.getParameterTypes().length == 0) { + break; + } + } + } + } + return constructor.newInstance(new Object[constructor.getParameterTypes().length]); + } catch (InstantiationException e) { + throw new RuntimeException(e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage(), e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + + private static Method getSetterMethod(Class cls, String property, Class valueCls) { + String name = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); + try { + return cls.getMethod(name, valueCls); + } catch (NoSuchMethodException e) { + for (Method method : cls.getMethods()) { + if (Modifier.isPublic(method.getModifiers()) + && method.getDeclaringClass() != Object.class + && method.getParameterTypes().length == 1 + && method.getName().equals(name)) { + return method; + } + } + } + return null; + } + + public static boolean isPojo(Class cls) { + return ! isBase(cls) + && ! Collection.class.isAssignableFrom(cls) + && ! Map.class.isAssignableFrom(cls); + } + + private static boolean isBase(Class cls) { + if (cls.isArray()) { + return isPrimitive(cls.getComponentType()); + } + return isPrimitive(cls); + } + + private static boolean isPrimitive(Class cls) { + return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class + || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Pool.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Pool.java new file mode 100644 index 0000000000..01dd5a8b03 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Pool.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +/** + * Pool. + * + * @author qian.lei + */ + +public interface Pool +{ + /** + * clear. + */ + void clear() throws Exception; + + /** + * close pool. + * + * @throws Exception. + */ + void close() throws Exception; + + /** + * borrow. + * + * @return object. + */ + T borrowObject() throws Exception; + + /** + * borrow. + * + * @param timeout timeout. + * @return object. + */ + T borrowObject(long timeout) throws Exception; + + /** + * return object. + * + * @param obj object. + */ + void returnObject(T obj) throws Exception; + + /** + * get factory. + * + * @return Factory instance. + */ + Factory getFactory(); + + /** + * get idle number. + * + * @return idle number. + */ + int getIdleNum(); + + /** + * get active number. + * + * @return active number. + */ + int getActiveNum(); + + /** + * pool factory. + */ + public interface Factory + { + /** + * make object. + * + * @return object. + * @throws Exception. + */ + T makeObject() throws Exception; + + /** + * destroy object. + * + * @param obj object. + * @throws Exception. + */ + void destroyObject(T obj) throws Exception; + + /** + * activate object. + * + * @param obj object. + */ + void activateObject(T obj); + + /** + * passivate object. + * + * @param obj object. + */ + void passivateObject(T obj); + +// /** +// * validate object. +// * +// * @param obj object. +// * @return valid or not. +// */ +// boolean validateObject(T obj); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Reference.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Reference.java new file mode 100644 index 0000000000..6e4c7fdd95 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Reference.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +/** + * TODO Comment of Reference + * + * @author william.liangf + */ +public class Reference { + + private T value; + + public void set(T value) { + this.value = value; + } + + public T get() { + return value; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ReflectUtils.java new file mode 100644 index 0000000000..229aa5b15e --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/ReflectUtils.java @@ -0,0 +1,759 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtMethod; +import javassist.NotFoundException; + +/** + * ReflectUtils + * + * @author qian.lei + */ + +public final class ReflectUtils +{ + /** + * void(V). + */ + public static final char JVM_VOID = 'V'; + + /** + * boolean(Z). + */ + public static final char JVM_BOOLEAN = 'Z'; + + /** + * byte(B). + */ + public static final char JVM_BYTE = 'B'; + + /** + * char(C). + */ + public static final char JVM_CHAR = 'C'; + + /** + * double(D). + */ + public static final char JVM_DOUBLE = 'D'; + + /** + * float(F). + */ + public static final char JVM_FLOAT = 'F'; + + /** + * int(I). + */ + public static final char JVM_INT = 'I'; + + /** + * long(J). + */ + public static final char JVM_LONG = 'J'; + + /** + * short(S). + */ + public static final char JVM_SHORT = 'S'; + + public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + + public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)"; + + public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)"; + + public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)"; + + public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))"; + + public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")"; + + public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX); + + public static final String METHOD_DESC_REGEX = "(?:("+JAVA_IDENT_REGEX+")?\\(("+DESC_REGEX+"*)\\)("+DESC_REGEX+")?)"; + + public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX); + + public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")"); + + public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V"); + + public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z"); + + /** + * is compatible. + * + * @param c class. + * @param o instance. + * @return compatible or not. + */ + public static boolean isCompatible(Class c, Object o) + { + boolean pt = c.isPrimitive(); + if( o == null ) + return !pt; + + if( pt ) + { + if( c == int.class ) + c = Integer.class; + else if( c == boolean.class ) + c = Boolean.class; + else if( c == long.class ) + c = Long.class; + else if( c == float.class ) + c = Float.class; + else if( c == double.class ) + c = Double.class; + else if( c == char.class ) + c = Character.class; + else if( c == byte.class ) + c = Byte.class; + else if( c == short.class ) + c = Short.class; + } + if( c == o.getClass() ) + return true; + return c.isInstance(o); + } + + /** + * is compatible. + * + * @param cs class array. + * @param os object array. + * @return compatible or not. + */ + public static boolean isCompatible(Class[] cs, Object[] os) + { + int len = cs.length; + if( len != os.length ) return false; + if( len == 0 ) return true; + for(int i=0;i cls) { + if (cls == null) + return null; + ProtectionDomain domain = cls.getProtectionDomain(); + if (domain == null) + return null; + CodeSource source = domain.getCodeSource(); + if (source == null) + return null; + URL location = source.getLocation(); + if (location == null) + return null; + return location.getFile(); + } + + /** + * get name. + * java.lang.Object[][].class => "java.lang.Object[][]" + * + * @param c class. + * @return name. + */ + public static String getName(Class c) + { + if( c.isArray() ) + { + StringBuilder sb = new StringBuilder(); + do + { + sb.append("[]"); + c = c.getComponentType(); + } + while( c.isArray() ); + + return c.getName() + sb.toString(); + } + return c.getName(); + } + + /** + * get method name. + * "void do(int)", "void do()", "int do(java.lang.String,boolean)" + * + * @param m method. + * @return name. + */ + public static String getName(final Method m) + { + StringBuilder ret = new StringBuilder(); + ret.append(getName(m.getReturnType())).append(' '); + ret.append(m.getName()).append('('); + Class[] parameterTypes = m.getParameterTypes(); + for(int i=0;i 0 ) + ret.append(','); + ret.append(getName(parameterTypes[i])); + } + ret.append(')'); + return ret.toString(); + } + + public static String getSignature(String methodName, Class[] parameterTypes) { + StringBuilder sb = new StringBuilder(methodName); + sb.append("("); + if (parameterTypes != null && parameterTypes.length > 0) { + boolean first = true; + for (Class type : parameterTypes) { + if (first) { + first = false; + } else { + sb.append(","); + } + sb.append(type.getName()); + } + } + sb.append(")"); + return sb.toString(); + } + + /** + * get constructor name. + * "()", "(java.lang.String,int)" + * + * @param c constructor. + * @return name. + */ + public static String getName(final Constructor c) + { + StringBuilder ret = new StringBuilder("("); + Class[] parameterTypes = c.getParameterTypes(); + for(int i=0;i 0 ) + ret.append(','); + ret.append(getName(parameterTypes[i])); + } + ret.append(')'); + return ret.toString(); + } + + /** + * get class desc. + * boolean[].class => "[Z" + * Object.class => "Ljava/lang/Object;" + * + * @param c class. + * @return desc. + * @throws NotFoundException + */ + public static String getDesc(Class c) + { + StringBuilder ret = new StringBuilder(); + + while( c.isArray() ) + { + ret.append('['); + c = c.getComponentType(); + } + + if( c.isPrimitive() ) + { + String t = c.getName(); + if( "void".equals(t) ) ret.append(JVM_VOID); + else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN); + else if( "byte".equals(t) ) ret.append(JVM_BYTE); + else if( "char".equals(t) ) ret.append(JVM_CHAR); + else if( "double".equals(t) ) ret.append(JVM_DOUBLE); + else if( "float".equals(t) ) ret.append(JVM_FLOAT); + else if( "int".equals(t) ) ret.append(JVM_INT); + else if( "long".equals(t) ) ret.append(JVM_LONG); + else if( "short".equals(t) ) ret.append(JVM_SHORT); + } + else + { + ret.append('L'); + ret.append(c.getName().replace('.', '/')); + ret.append(';'); + } + return ret.toString(); + } + + /** + * get class array desc. + * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;" + * + * @param cs class array. + * @return desc. + * @throws NotFoundException + */ + public static String getDesc(final Class[] cs) + { + if( cs.length == 0 ) + return ""; + + StringBuilder sb = new StringBuilder(64); + for( Class c : cs ) + sb.append(getDesc(c)); + return sb.toString(); + } + + /** + * get method desc. + * int do(int arg1) => "do(I)I" + * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V" + * + * @param m method. + * @return desc. + */ + public static String getDesc(final Method m) + { + StringBuilder ret = new StringBuilder(m.getName()).append('('); + Class[] parameterTypes = m.getParameterTypes(); + for(int i=0;i c) + { + StringBuilder ret = new StringBuilder("("); + Class[] parameterTypes = c.getParameterTypes(); + for(int i=0;i[] parameterTypes = m.getParameterTypes(); + for(int i=0;i "Ljava/lang/Object;" + * boolean[].class => "[Z" + * + * @param c class. + * @return desc. + * @throws NotFoundException + */ + public static String getDesc(final CtClass c) throws NotFoundException + { + StringBuilder ret = new StringBuilder(); + if( c.isArray() ) + { + ret.append('['); + ret.append(getDesc(c.getComponentType())); + } + else if( c.isPrimitive() ) + { + String t = c.getName(); + if( "void".equals(t) ) ret.append(JVM_VOID); + else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN); + else if( "byte".equals(t) ) ret.append(JVM_BYTE); + else if( "char".equals(t) ) ret.append(JVM_CHAR); + else if( "double".equals(t) ) ret.append(JVM_DOUBLE); + else if( "float".equals(t) ) ret.append(JVM_FLOAT); + else if( "int".equals(t) ) ret.append(JVM_INT); + else if( "long".equals(t) ) ret.append(JVM_LONG); + else if( "short".equals(t) ) ret.append(JVM_SHORT); + } + else + { + ret.append('L'); + ret.append(c.getName().replace('.','/')); + ret.append(';'); + } + return ret.toString(); + } + + /** + * get method desc. + * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V" + * + * @param m method. + * @return desc. + */ + public static String getDesc(final CtMethod m) throws NotFoundException + { + StringBuilder ret = new StringBuilder(m.getName()).append('('); + CtClass[] parameterTypes = m.getParameterTypes(); + for(int i=0;i "[[Ljava/util/Map;" + * + * @param name name. + * @return desc. + */ + public static String name2desc(String name) + { + StringBuilder sb = new StringBuilder(); + int c = 0,index = name.indexOf('['); + if( index > 0 ) + { + c = ( name.length() - index ) / 2; + name = name.substring(0,index); + } + while( c-- > 0 ) sb.append("["); + if( "void".equals(name) ) sb.append(JVM_VOID); + else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN); + else if( "byte".equals(name) ) sb.append(JVM_BYTE); + else if( "char".equals(name) ) sb.append(JVM_CHAR); + else if( "double".equals(name) ) sb.append(JVM_DOUBLE); + else if( "float".equals(name) ) sb.append(JVM_FLOAT); + else if( "int".equals(name) ) sb.append(JVM_INT); + else if( "long".equals(name) ) sb.append(JVM_LONG); + else if( "short".equals(name) ) sb.append(JVM_SHORT); + else sb.append('L').append(name.replace('.', '/')).append(';'); + return sb.toString(); + } + + /** + * desc to name. + * "[[I" => "int[][]" + * + * @param desc desc. + * @return name. + */ + public static String desc2name(String desc) + { + StringBuilder sb = new StringBuilder(); + int c = desc.lastIndexOf('[') + 1; + if( desc.length() == c+1 ) + { + switch( desc.charAt(c) ) + { + case JVM_VOID: { sb.append("void"); break; } + case JVM_BOOLEAN: { sb.append("boolean"); break; } + case JVM_BYTE: { sb.append("byte"); break; } + case JVM_CHAR: { sb.append("char"); break; } + case JVM_DOUBLE: { sb.append("double"); break; } + case JVM_FLOAT: { sb.append("float"); break; } + case JVM_INT: { sb.append("int"); break; } + case JVM_LONG: { sb.append("long"); break; } + case JVM_SHORT: { sb.append("short"); break; } + default: + throw new RuntimeException(); + } + } + else + { + sb.append(desc.substring(c+1, desc.length()-1).replace('/','.')); + } + while( c-- > 0 ) sb.append("[]"); + return sb.toString(); + } + + public static Class forName(String name) { + try { + return name2class(name); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e); + } + } + + /** + * name to class. + * "boolean" => boolean.class + * "java.util.Map[][]" => java.util.Map[][].class + * + * @param name name. + * @return Class instance. + */ + public static Class name2class(String name) throws ClassNotFoundException + { + return name2class(ClassHelper.getClassLoader(), name); + } + + /** + * name to class. + * "boolean" => boolean.class + * "java.util.Map[][]" => java.util.Map[][].class + * + * @param cl ClassLoader instance. + * @param name name. + * @return Class instance. + */ + public static Class name2class(ClassLoader cl, String name) throws ClassNotFoundException + { + int c = 0, index = name.indexOf('['); + if( index > 0 ) + { + c = ( name.length() - index ) / 2; + name = name.substring(0, index); + } + if( c > 0 ) + { + StringBuilder sb = new StringBuilder(); + while( c-- > 0 ) + sb.append("["); + + if( "void".equals(name) ) sb.append(JVM_VOID); + else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN); + else if( "byte".equals(name) ) sb.append(JVM_BYTE); + else if( "char".equals(name) ) sb.append(JVM_CHAR); + else if( "double".equals(name) ) sb.append(JVM_DOUBLE); + else if( "float".equals(name) ) sb.append(JVM_FLOAT); + else if( "int".equals(name) ) sb.append(JVM_INT); + else if( "long".equals(name) ) sb.append(JVM_LONG); + else if( "short".equals(name) ) sb.append(JVM_SHORT); + else sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;" + name = sb.toString(); + } + else + { + if( "void".equals(name) ) return void.class; + else if( "boolean".equals(name) ) return boolean.class; + else if( "byte".equals(name) ) return byte.class; + else if( "char".equals(name) ) return char.class; + else if( "double".equals(name) ) return double.class; + else if( "float".equals(name) ) return float.class; + else if( "int".equals(name) ) return int.class; + else if( "long".equals(name) ) return long.class; + else if( "short".equals(name) ) return short.class; + } + + if( cl == null ) + cl = ClassHelper.getClassLoader(); + return Class.forName(name, true, cl); + } + + /** + * desc to class. + * "[Z" => boolean[].class + * "[[Ljava/util/Map;" => java.util.Map[][].class + * + * @param desc desc. + * @return Class instance. + * @throws ClassNotFoundException + */ + public static Class desc2class(String desc) throws ClassNotFoundException + { + return desc2class(ClassHelper.getClassLoader(), desc); + } + + /** + * desc to class. + * "[Z" => boolean[].class + * "[[Ljava/util/Map;" => java.util.Map[][].class + * + * @param cl ClassLoader instance. + * @param desc desc. + * @return Class instance. + * @throws ClassNotFoundException + */ + public static Class desc2class(ClassLoader cl, String desc) throws ClassNotFoundException + { + switch( desc.charAt(0) ) + { + case JVM_VOID: return void.class; + case JVM_BOOLEAN: return boolean.class; + case JVM_BYTE: return byte.class; + case JVM_CHAR: return char.class; + case JVM_DOUBLE: return double.class; + case JVM_FLOAT: return float.class; + case JVM_INT: return int.class; + case JVM_LONG: return long.class; + case JVM_SHORT: return short.class; + case 'L': + desc = desc.substring(1, desc.length()-1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object" + break; + case '[': + desc = desc.replace('/', '.'); // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;" + break; + default: + throw new ClassNotFoundException("Class not found: " + desc); + } + + if( cl == null ) + cl = ClassHelper.getClassLoader(); + return Class.forName(desc, true, cl); + } + + /** + * get class array instance. + * + * @param desc desc. + * @return Class class array. + * @throws ClassNotFoundException + */ + public static Class[] desc2classArray(String desc) throws ClassNotFoundException + { + return desc2classArray(ClassHelper.getClassLoader(), desc); + } + + /** + * get class array instance. + * + * @param cl ClassLoader instance. + * @param desc desc. + * @return Class[] class array. + * @throws ClassNotFoundException + */ + public static Class[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException + { + if( desc.length() == 0 ) + return EMPTY_CLASS_ARRAY; + + List> cs = new ArrayList>(); + Matcher m = DESC_PATTERN.matcher(desc); + while(m.find()) + cs.add(desc2class(cl, m.group())); + return cs.toArray(EMPTY_CLASS_ARRAY); + } + + /** + * 根据方法签名从类中找出方法。 + * + * @param clazz 查找的类。 + * @param methodSignature 方法签名,形如method1(int, String)。也允许只给方法名不参数只有方法名,形如method2。 + * @return 返回查找到的方法。 + * @throws NoSuchMethodException + * @throws ClassNotFoundException + * @throws IllegalStateException 给定的方法签名找到多个方法(方法签名中没有指定参数,又有有重载的方法的情况) + */ + public static Method findMethodByMethodSignature(Class clazz, String methodName, String[] parameterTypes) + throws NoSuchMethodException, ClassNotFoundException { + if (parameterTypes == null) { + List finded = new ArrayList(); + for (Method m : clazz.getMethods()) { + if (m.getName().equals(methodName)) { + finded.add(m); + } + } + if (finded.isEmpty()) { + throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz); + } + if(finded.size() > 1) { + String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.", + methodName, clazz.getName(), finded.size()); + throw new IllegalStateException(msg); + } + return finded.get(0); + } else { + Class[] types = new Class[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i ++) { + types[i] = ReflectUtils.name2class(parameterTypes[i]); + } + return clazz.getMethod(methodName, types); + } + } + + public static Method findMethodByMethodName(Class clazz, String methodName) + throws NoSuchMethodException, ClassNotFoundException { + return findMethodByMethodSignature(clazz, methodName, null); + } + + public static Constructor findConstructor(Class clazz, Class paramType) throws NoSuchMethodException { + Constructor targetConstructor; + try { + targetConstructor = clazz.getConstructor(new Class[] {paramType}); + } catch (NoSuchMethodException e) { + targetConstructor = null; + Constructor[] constructors = clazz.getConstructors(); + for (Constructor constructor : constructors) { + if (Modifier.isPublic(constructor.getModifiers()) + && constructor.getParameterTypes().length == 1 + && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) { + targetConstructor = constructor; + break; + } + } + if (targetConstructor == null) { + throw e; + } + } + return targetConstructor; + } + + private ReflectUtils(){} +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Service.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Service.java new file mode 100644 index 0000000000..7fdc069241 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Service.java @@ -0,0 +1,300 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.TreeSet; + +/** + * Copy form openjdk sun.misc.Service. + * http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html#Service%20Provider + * + * @author william.liangf + * @author qian.lei + * @author ding.lid + */ +public final class Service { + + private static final String prefix = "META-INF/services/"; + + private Service() { + } + + private static void fail(Class service, String msg, Throwable cause) { + IllegalStateException sce = new IllegalStateException(service.getName() + ": " + + msg); + sce.initCause(cause); + throw sce; + } + + private static void fail(Class service, String msg) { + throw new IllegalStateException(service.getName() + ": " + msg); + } + + private static void fail(Class service, URL u, int line, String msg) { + fail(service, u + ":" + line + ": " + msg); + } + + /** + * Parse a single line from the given configuration file, adding the name on + * the line to both the names list and the returned set iff the name is not + * already a member of the returned set. + */ + private static int parseLine(Class service, URL u, BufferedReader r, int lc, + List names, Set returned) throws IOException { + String ln = r.readLine(); + if (ln == null) { + return -1; + } + int ci = ln.indexOf('#'); + if (ci >= 0) + ln = ln.substring(0, ci); + ln = ln.trim(); + int n = ln.length(); + if (n != 0) { + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) + fail(service, u, lc, "Illegal configuration-file syntax"); + int cp = ln.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) + fail(service, u, lc, "Illegal provider-class name: " + ln); + for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { + cp = ln.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) + fail(service, u, lc, "Illegal provider-class name: " + ln); + } + if (!returned.contains(ln)) { + names.add(ln); + returned.add(ln); + } + } + return lc + 1; + } + + /** + * Parse the content of the given URL as a provider-configuration file. + * + * @param service The service class for which providers are being sought; + * used to construct error detail strings + * @param url The URL naming the configuration file to be parsed + * @param returned A Set containing the names of provider classes that have + * already been returned. This set will be updated to contain the + * names that will be yielded from the returned Iterator + * . + * @return A (possibly empty) Iterator that will yield the + * provider-class names in the given configuration file that are not + * yet members of the returned set + * @throws ServiceConfigurationError If an I/O error occurs while reading + * from the given URL, or if a configuration-file format error + * is detected + */ + private static Iterator parse(Class service, URL u, Set returned) { + InputStream in = null; + BufferedReader r = null; + ArrayList names = new ArrayList(); + try { + in = u.openStream(); + r = new BufferedReader(new InputStreamReader(in, "utf-8")); + int lc = 1; + while ((lc = parseLine(service, u, r, lc, names, returned)) >= 0) + ; + } catch (IOException x) { + fail(service, ": " + x); + } finally { + try { + if (r != null) + r.close(); + if (in != null) + in.close(); + } catch (IOException y) { + fail(service, ": " + y); + } + } + return names.iterator(); + } + + /** + * Private inner class implementing fully-lazy provider lookup + */ + private static class LazyIterator implements Iterator> { + + Class service; + ClassLoader loader; + Enumeration configs = null; + Iterator pending = null; + Set returned = new TreeSet(); + String nextName = null; + + private LazyIterator(Class service, ClassLoader loader) { + this.service = service; + this.loader = loader; + } + + public boolean hasNext() { + if (nextName != null) { + return true; + } + if (configs == null) { + try { + String fullName = prefix + service.getName(); + if (loader == null) + configs = ClassLoader.getSystemResources(fullName); + else + configs = loader.getResources(fullName); + } catch (IOException x) { + fail(service, ": " + x); + } + } + while ((pending == null) || !pending.hasNext()) { + if (!configs.hasMoreElements()) { + return false; + } + pending = parse(service, (URL) configs.nextElement(), returned); + } + nextName = (String) pending.next(); + return true; + } + + @SuppressWarnings("unchecked") + public Class next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + String cn = nextName; + nextName = null; + try { + return (Class) Class.forName(cn, true, loader); + } catch (ClassNotFoundException x) { + fail(service, "Provider " + cn + " not found"); + } catch (Exception x) { + fail(service, "Provider " + cn + " could not be instantiated: " + x, x); + } + return null; /* This cannot happen */ + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Locates and incrementally instantiates the available providers of a given + * service using the given class loader. + *

    + * This method transforms the name of the given service class into a + * provider-configuration filename as described above and then uses the + * getResources method of the given class loader to find all + * available files with that name. These files are then read and parsed to + * produce a list of provider-class names. The iterator that is returned + * uses the given class loader to lookup and then instantiate each element + * of the list. + *

    + * Because it is possible for extensions to be installed into a running Java + * virtual machine, this method may return different results each time it is + * invoked. + *

    + * + * @param service The service's abstract service class + * @param loader The class loader to be used to load provider-configuration + * files and instantiate provider classes, or null if + * the system class loader (or, failing that the bootstrap class + * loader) is to be used + * @return An Iterator that yields provider objects for the given + * service, in some arbitrary order. The iterator will throw a + * ServiceConfigurationError if a provider-configuration + * file violates the specified format or if a provider class cannot + * be found and instantiated. + * @throws ServiceConfigurationError If a provider-configuration file + * violates the specified format or names a provider class that + * cannot be found and instantiated + * @see #providers(java.lang.Class) + * @see #installedProviders(java.lang.Class) + */ + public static Iterator> providers(Class service, ClassLoader loader) { + return new LazyIterator(service, loader); + } + + /** + * Locates and incrementally instantiates the available providers of a given + * service using the context class loader. This convenience method is + * equivalent to + * + *

    +     * ClassLoader cl = Thread.currentThread().getContextClassLoader();
    +     * return Service.providers(service, cl);
    +     * 
    + * + * @param service The service's abstract service class + * @return An Iterator that yields provider objects for the given + * service, in some arbitrary order. The iterator will throw a + * ServiceConfigurationError if a provider-configuration + * file violates the specified format or if a provider class cannot + * be found and instantiated. + * @throws ServiceConfigurationError If a provider-configuration file + * violates the specified format or names a provider class that + * cannot be found and instantiated + * @see #providers(java.lang.Class, java.lang.ClassLoader) + */ + public static Iterator> providers(Class service) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + return Service.providers(service, cl); + } + + /** + * Locates and incrementally instantiates the available providers of a given + * service using the extension class loader. This convenience method simply + * locates the extension class loader, call it extClassLoader, and + * then does + * + *
    +     * return Service.providers(service, extClassLoader);
    +     * 
    + * + * If the extension class loader cannot be found then the system class + * loader is used; if there is no system class loader then the bootstrap + * class loader is used. + * + * @param service The service's abstract service class + * @return An Iterator that yields provider objects for the given + * service, in some arbitrary order. The iterator will throw a + * ServiceConfigurationError if a provider-configuration + * file violates the specified format or if a provider class cannot + * be found and instantiated. + * @throws ServiceConfigurationError If a provider-configuration file + * violates the specified format or names a provider class that + * cannot be found and instantiated + * @see #providers(java.lang.Class, java.lang.ClassLoader) + */ + public static Iterator> installedProviders(Class service) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + ClassLoader prev = null; + while (cl != null) { + prev = cl; + cl = cl.getParent(); + } + return Service.providers(service, prev); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Stack.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Stack.java new file mode 100644 index 0000000000..13d6347d55 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/Stack.java @@ -0,0 +1,147 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.ArrayList; +import java.util.EmptyStackException; +import java.util.List; + +/** + * Stack. + * + * @author qian.lei + */ + +public class Stack +{ + private int mSize = 0; + + private List mElements = new ArrayList(); + + public Stack(){} + + /** + * push. + * + * @param ele + */ + public void push(E ele) + { + if( mElements.size() > mSize ) + mElements.set(mSize, ele); + else + mElements.add(ele); + mSize++; + } + + /** + * pop. + * + * @return the last element. + */ + public E pop() + { + if( mSize == 0 ) + throw new EmptyStackException(); + return mElements.set(--mSize, null); + } + + /** + * peek. + * + * @return the last element. + */ + public E peek() + { + if( mSize == 0 ) + throw new EmptyStackException(); + return mElements.get(mSize-1); + } + + /** + * get. + * + * @param index index. + * @return element. + */ + public E get(int index) + { + if( index >= mSize ) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mSize); + + return index < 0 ? mElements.get(index+mSize) : mElements.get(index); + } + + /** + * set. + * + * @param index index. + * @param value element. + * @return old element. + */ + public E set(int index, E value) + { + if( index >= mSize ) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mSize); + + return mElements.set(index < 0 ? index + mSize : index, value); + } + + /** + * remove. + * + * @param index + * @return + */ + public E remove(int index) + { + if( index >= mSize ) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mSize); + + E ret = mElements.remove(index < 0 ? index + mSize : index); + mSize--; + return ret; + } + + /** + * get stack size. + * + * @return size. + */ + public int size() + { + return mSize; + } + + /** + * is empty. + * + * @return empty or not. + */ + public boolean isEmpty() + { + return mSize == 0; + } + + /** + * clear stack. + */ + public void clear() + { + mSize = 0; + mElements.clear(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java new file mode 100644 index 0000000000..16ccc0d763 --- /dev/null +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/StringUtils.java @@ -0,0 +1,371 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.io.UnsafeStringWriter; + +/** + * StringUtils + * + * @author qian.lei + */ + +public final class StringUtils +{ + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + + private static final Pattern KVP_PATTERN = Pattern.compile("([_.a-zA-Z0-9][-_.a-zA-Z0-9]*)[=](.*)"); //key value pair pattern. + + private static final Pattern INT_PATTERN = Pattern.compile("^\\d+$"); + + public static boolean isBlank(String str) + { + if( str == null || str.length() == 0 ) + return true; + return false; + } + + /** + * is empty string. + * + * @param str source string. + * @return is empty. + */ + public static boolean isEmpty(String str) + { + if( str == null || str.length() == 0 ) + return true; + return false; + } + + /** + * is not empty string. + * + * @param str source string. + * @return is not empty. + */ + public static boolean isNotEmpty(String str) + { + return str != null && str.length() > 0; + } + + /** + * is integer string. + * + * @param str + * @return + */ + public static boolean isInteger(String str) { + if (str == null || str.length() == 0) + return false; + return INT_PATTERN.matcher(str).matches(); + } + + public static int parseInteger(String str) { + if (! isInteger(str)) + return 0; + return Integer.parseInt(str); + } + + /** + * Returns true if s is a legal Java identifier.

    + * more info. + */ + public static boolean isJavaIdentifier(String s) { + if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) { + return false; + } + for (int i=1; i 0 && values != null && values.length > 0) { + for (String v : values) { + if (value.equals(v)) { + return true; + } + } + } + return false; + } + + /** + * + * @param e + * @return + */ + public static String toString(Throwable e) { + UnsafeStringWriter w = new UnsafeStringWriter(); + PrintWriter p = new PrintWriter(w); + p.print(e.getClass().getName()); + if (e.getMessage() != null) { + p.print(e.getMessage()); + } + p.println(); + try { + e.printStackTrace(p); + return w.toString(); + } finally { + p.close(); + } + } + + /** + * + * @param msg + * @param e + * @return + */ + public static String toString(String msg, Throwable e) { + UnsafeStringWriter w = new UnsafeStringWriter(); + w.write(msg + "\n"); + PrintWriter p = new PrintWriter(w); + try { + e.printStackTrace(p); + return w.toString(); + } finally { + p.close(); + } + } + + /** + * translat. + * + * @param src source string. + * @param from src char table. + * @param to target char table. + * @return String. + */ + public static String translat(String src, String from, String to) + { + if( isEmpty(src) ) return src; + StringBuilder sb = null; + int ix; + char c; + for(int i=0,len=src.length();i list = null; + char c; + int ix = 0,len=str.length(); + for(int i=0;i(); + list.add(str.substring(ix, i)); + ix = i + 1; + } + } + if( ix > 0 ) + list.add(str.substring(ix)); + return list == null ? EMPTY_STRING_ARRAY : (String[])list.toArray(EMPTY_STRING_ARRAY); + } + + /** + * join string. + * + * @param array String array. + * @return String. + */ + public static String join(String[] array) + { + if( array.length == 0 ) return ""; + StringBuilder sb = new StringBuilder(); + for( String s : array ) + sb.append(s); + return sb.toString(); + } + + /** + * join string like javascript. + * + * @param array String array. + * @param split split + * @return String. + */ + public static String join(String[] array, char split) + { + if( array.length == 0 ) return ""; + StringBuilder sb = new StringBuilder(); + for(int i=0;i 0 ) + sb.append(split); + sb.append(array[i]); + } + return sb.toString(); + } + + /** + * join string like javascript. + * + * @param array String array. + * @param split split + * @return String. + */ + public static String join(String[] array, String split) + { + if( array.length == 0 ) return ""; + StringBuilder sb = new StringBuilder(); + for(int i=0;i 0 ) + sb.append(split); + sb.append(array[i]); + } + return sb.toString(); + } + + public static String join(Collection coll, String split) { + if(coll.isEmpty()) return ""; + + StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for(String s : coll) { + if(isFirst) isFirst = false; else sb.append(split); + sb.append(s); + } + return sb.toString(); + } + + /** + * parse key-value pair. + * + * @param str string. + * @param itemSeparator item separator. + * @return key-value map; + */ + private static Map parseKeyValuePair(String str, String itemSeparator) + { + String[] tmp = str.split(itemSeparator); + Map map = new HashMap(tmp.length); + for(int i=0;i map = StringUtils.parseQueryString(qs); + return map.get(key); + } + + /** + * parse query string to Parameters. + * + * @param qs query string. + * @return Parameters instance. + */ + public static Map parseQueryString(String qs) + { + if( qs == null || qs.length() == 0 ) + return new HashMap(); + return parseKeyValuePair(qs, "\\&"); + } + + public static String getServiceKey(Map ps) { + StringBuilder buf = new StringBuilder(); + String group = ps.get(Constants.GROUP_KEY); + if (group != null && group.length()>0){ + buf.append(group).append("/"); + } + buf.append(ps.get(Constants.INTERFACE_KEY)); + String version = ps.get(Constants.VERSION_KEY); + if (version!= null && version.length()>0){ + buf.append(":").append(version); + } + return buf.toString(); + } + + public static String toQueryString(Map ps) { + StringBuilder buf = new StringBuilder(); + if (ps != null && ps.size() > 0) { + for (Map.Entry entry : new TreeMap(ps).entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (key != null && key.length() > 0 + && value != null && value.length() > 0) { + if (buf.length() > 0) { + buf.append("&"); + } + buf.append(key); + buf.append("="); + buf.append(value); + } + } + } + return buf.toString(); + } + + private StringUtils(){} +} \ No newline at end of file diff --git a/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.serialize.Serialization b/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.serialize.Serialization new file mode 100644 index 0000000000..09bd8e97e5 --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.serialize.Serialization @@ -0,0 +1,6 @@ +com.alibaba.dubbo.common.serialize.support.dubbo.DubboSerialization +com.alibaba.dubbo.common.serialize.support.hessian.Hessian2Serialization +com.alibaba.dubbo.common.serialize.support.java.JavaSerialization +com.alibaba.dubbo.common.serialize.support.java.CompactedJavaSerialization +com.alibaba.dubbo.common.serialize.support.json.JsonSerialization +com.alibaba.dubbo.common.serialize.support.json.FastJsonSerialization \ No newline at end of file diff --git a/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker b/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker new file mode 100644 index 0000000000..3d14c969cd --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker @@ -0,0 +1,2 @@ +com.alibaba.dubbo.common.status.support.MemoryStatusChecker +com.alibaba.dubbo.common.status.support.LoadStatusChecker \ No newline at end of file diff --git a/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.threadpool.ThreadPool b/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.threadpool.ThreadPool new file mode 100644 index 0000000000..91dae06bc7 --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/services/com.alibaba.dubbo.common.threadpool.ThreadPool @@ -0,0 +1,2 @@ +com.alibaba.dubbo.common.threadpool.support.fixed.FixedThreadPool +com.alibaba.dubbo.common.threadpool.support.cached.CachedThreadPool \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/MixinTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/MixinTest.java new file mode 100644 index 0000000000..15a824fdbc --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/MixinTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import com.alibaba.dubbo.common.bytecode.Mixin; + +import junit.framework.TestCase; + +public class MixinTest extends TestCase +{ + public void testMain() throws Exception + { + Mixin mixin = Mixin.mixin(new Class[]{ I1.class, I2.class, I3.class }, new Class[]{ C1.class, C2.class }); + Object o = mixin.newInstance(new Object[]{ new C1(), new C2() }); + assertEquals(o instanceof I1, true); + assertEquals(o instanceof I2, true); + assertEquals(o instanceof I3, true); + ((I1)o).m1(); + ((I2)o).m2(); + ((I3)o).m3(); + } + + interface I1{ void m1(); } + interface I2{ void m2(); } + interface I3{ void m3(); } + + class C1 implements Mixin.MixinAware + { + public void m1() + { + System.out.println("c1.m1();"); + } + + public void m2() + { + System.out.println("c1.m2();"); + } + + public void setMixinInstance(Object mi) + { + System.out.println("setMixinInstance:" + mi); + } + } + + class C2 implements Mixin.MixinAware + { + public void m3() + { + System.out.println("c2.m3();"); + } + + public void setMixinInstance(Object mi) + { + System.out.println("setMixinInstance:" + mi); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/ProxyTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/ProxyTest.java new file mode 100644 index 0000000000..069323d504 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/ProxyTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.bytecode.Proxy; + +import junit.framework.TestCase; + +public class ProxyTest extends TestCase +{ + public void testMain() throws Exception + { + Proxy proxy = Proxy.getProxy(ITest.class, ITest.class); + ITest instance = (ITest)proxy.newInstance(new InvocationHandler(){ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + if( "getName".equals(method.getName()) ) + { + assertEquals(args.length, 0); + } + else if( "setName".equals(method.getName()) ) + { + assertEquals(args.length, 2); + assertEquals(args[0], "qianlei"); + assertEquals(args[1], "hello"); + } + return null; + } + }); + + assertNull(instance.getName()); + instance.setName("qianlei", "hello"); + } + + public static interface ITest + { + String getName(); + + void setName(String name, String name2); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/URLTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/URLTest.java new file mode 100644 index 0000000000..a1fb2b8fcb --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/URLTest.java @@ -0,0 +1,536 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; + +import static org.hamcrest.CoreMatchers.*; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import com.alibaba.dubbo.common.utils.CollectionUtils; + +/** + * @author ding.lid + * @author william.liangf + */ +public class URLTest { + + @Test + public void test_valueOf_noProtocolAndHost() throws Exception { + URL url = URL.valueOf("/context/path?version=1.0.0&application=morgan"); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + + url = URL.valueOf("context/path?version=1.0.0&application=morgan"); + // ^^^^^^^ Caution , parse as host + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("context", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_valueOf_noProtocol() throws Exception { + URL url = URL.valueOf("10.20.130.230"); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals(null, url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("10.20.130.230:20880"); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals(null, url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("10.20.130.230/context/path"); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("10.20.130.230:20880/context/path"); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertNull(url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_valueOf_noHost() throws Exception { + URL url = URL.valueOf("file:///home/user1/router.js"); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + // Caution!! + url = URL.valueOf("file://home/user1/router.js"); + // ^^ only tow slash! + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("home", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + + url = URL.valueOf("file:/home/user1/router.js"); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("file:///d:/home/user1/router.js"); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("d:/home/user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("file:///home/user1/router.js?p1=v1&p2=v2"); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(2, url.getParameters().size()); + Map params = new HashMap(); + params.put("p1", "v1"); + params.put("p2", "v2"); + assertEquals(params, url.getParameters()); + + url = URL.valueOf("file:/home/user1/router.js?p1=v1&p2=v2"); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(2, url.getParameters().size()); + params = new HashMap(); + params.put("p1", "v1"); + params.put("p2", "v2"); + assertEquals(params, url.getParameters()); + } + + @Test + public void test_valueOf_WithProtocolHost() throws Exception { + URL url = URL.valueOf("dubbo://10.20.130.230"); + assertEquals("dubbo", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals(null, url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("dubbo://10.20.130.230:20880/context/path"); + assertEquals("dubbo", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880"); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals(null, url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880?version=1.0.0"); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals(null, url.getPath()); + assertEquals(1, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue"); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + assertEquals("noValue", url.getParameter("noValue")); + } + + @Test + public void test_valueOf_Exception_noProtocol() throws Exception { + try { + URL.valueOf("://1.2.3.4:8080/path"); + fail(); + } catch (IllegalStateException expected) { + assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", expected.getMessage()); + } + } + + @Test + public void test_getAddress() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertEquals("10.20.130.230:20880", url1.getAddress()); + } + + @Test + public void test_getAbsolutePath() throws Exception { + URL url = new URL("p1", "1.2.2.2", 33); + assertEquals(null, url.getAbsolutePath()); + + url = new URL("file", null, 90, "/home/user1/route.js"); + assertEquals("/home/user1/route.js", url.getAbsolutePath()); + } + + @Test + public void test_equals() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + + Map params = new HashMap(); + params.put("version", "1.0.0"); + params.put("application", "morgan"); + URL url2 = new URL("dubbo", "10.20.130.230", 20880, "context/path", params); + + assertEquals(url1, url2); + } + + @Test + public void test_toString() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertThat(url1.toString(), anyOf( + equalTo("dubbo://10.20.130.230:20880/context/path?version=1.0.0&application=morgan"), + equalTo("dubbo://10.20.130.230:20880/context/path?application=morgan&version=1.0.0")) + ); + } + + @Test + public void test_toFullString() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertThat(url1.toFullString(), anyOf( + equalTo("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"), + equalTo("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&version=1.0.0")) + ); + } + + @Test + public void test_set_methods() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + + url = url.setHost("host"); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setPort(1); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals(1, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setPath("path"); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setProtocol("protocol"); + + assertEquals("protocol", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setUsername("username"); + + assertEquals("protocol", url.getProtocol()); + assertEquals("username", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setPassword("password"); + + assertEquals("protocol", url.getProtocol()); + assertEquals("username", url.getUsername()); + assertEquals("password", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_removeParameters() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); + + url = url.removeParameter("version"); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); + url = url.removeParameters("version", "application"); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); + url = url.removeParameters(Arrays.asList("version", "application")); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + } + + @Test + public void test_addParameters() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameters(CollectionUtils.toStringMap("k1", "v1", "k2", "v2")); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameters("k1", "v1", "k2", "v2", "application", "xxx"); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("xxx", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParametersIfAbsent(CollectionUtils.toStringMap("k1", "v1", "k2", "v2", "application", "xxx")); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameter("k1", "v1"); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameter("application", "xxx"); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(1, url.getParameters().size()); + assertEquals("xxx", url.getParameter("application")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameterIfAbsent("application", "xxx"); + + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(1, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_windowAbsolutePathBeginWithSlashIsValid() throws Exception { + final String osProperty = System.getProperties().getProperty("os.name"); + if(!osProperty.toLowerCase().contains("windows")) return; + + System.out.println("Test Windows valid path string."); + + File f0 = new File("C:/Windows"); + File f1 = new File("/C:/Windows"); + + File f2 = new File("C:\\Windows"); + File f3 = new File("/C:\\Windows"); + File f4 = new File("\\C:\\Windows"); + + assertEquals(f0, f1); + assertEquals(f0, f2); + assertEquals(f0, f3); + assertEquals(f0, f4); + } + + @Test + public void test_javaNetUrl() throws Exception { + java.net.URL url = new java.net.URL("http://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan#anchor1"); + + assertEquals("http", url.getProtocol()); + assertEquals("admin:hello1234", url.getUserInfo()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("/context/path", url.getPath()); + assertEquals("version=1.0.0&application=morgan", url.getQuery()); + assertEquals("anchor1", url.getRef()); + + assertEquals("admin:hello1234@10.20.130.230:20880", url.getAuthority()); + assertEquals("/context/path?version=1.0.0&application=morgan", url.getFile()); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/WrapperTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/WrapperTest.java new file mode 100644 index 0000000000..bb58caa460 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/WrapperTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common; + +import com.alibaba.dubbo.common.bytecode.Wrapper; + +import junit.framework.TestCase; + +public class WrapperTest extends TestCase +{ + public void testMain() throws Exception + { + Wrapper w = Wrapper.getWrapper(I1.class); + String[] ns = w.getDeclaredMethodNames(); + assertEquals(ns.length, 5); + ns = w.getMethodNames(); + assertEquals(ns.length, 6); + + Object obj = new Impl1(); + assertEquals(w.getPropertyValue(obj, "name"), "you name"); + + w.setPropertyValue(obj, "name", "changed"); + assertEquals(w.getPropertyValue(obj, "name"), "changed"); + + w.invokeMethod(obj, "hello", new Class[] {String.class}, new Object[]{ "qianlei" }); + } + + public static class Impl0 + { + public float a,b,c; + } + + public static interface I0 + { + String getName(); + } + + public static interface I1 extends I0 + { + void setName(String name); + + void hello(String name); + + int showInt(int v); + + void setFloat(float f); + + float getFloat(); + } + + public static class Impl1 implements I1 + { + private String name = "you name"; + + private float fv = 0; + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public void hello(String name) + { + System.out.println("hello " + name); + } + + public int showInt(int v) + { + return v; + } + + public float getFloat() + { + return fv; + } + + public void setFloat(float f) + { + fv = f; + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/bytecode/ClassGeneratorTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/bytecode/ClassGeneratorTest.java new file mode 100644 index 0000000000..420aa2c821 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/bytecode/ClassGeneratorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.bytecode; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +public class ClassGeneratorTest extends TestCase +{ + @SuppressWarnings("unchecked") + public void testMain() throws Exception + { + Bean b = new Bean(); + Field fname = null, fs[] = Bean.class.getDeclaredFields(); + for( Field f : fs ) + { + f.setAccessible(true); + if( f.getName().equals("name") ) + fname = f; + } + + ClassGenerator cg = ClassGenerator.newInstance(); + cg.setClassName(Bean.class.getName() + "$Builder"); + cg.addInterface(Builder.class); + + cg.addField("public static java.lang.reflect.Field FNAME;"); + + cg.addMethod("public Object getName("+Bean.class.getName()+" o){ boolean[][][] bs = new boolean[0][][]; return (String)FNAME.get($1); }"); + cg.addMethod("public void setName("+Bean.class.getName()+" o, Object name){ FNAME.set($1, $2); }"); + + cg.addDefaultConstructor(); + Class cl = cg.toClass(); + cl.getField("FNAME").set(null, fname); + + System.out.println(cl.getName()); + Builder builder = (Builder)cl.newInstance(); + System.out.println(b.getName()); + builder.setName(b, "ok"); + System.out.println(b.getName()); + } +} + +class Bean +{ + int age = 30; + + private String name = "qianlei"; + + public int getAge() + { + return age; + } + + public String getName() + { + return name; + } +} + +interface Builder +{ + T getName(Bean bean); + + void setName(Bean bean, T name); +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ExtensionLoaderTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ExtensionLoaderTest.java new file mode 100644 index 0000000000..ca411be27d --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ExtensionLoaderTest.java @@ -0,0 +1,383 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader; + +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; +import static org.junit.matchers.JUnitMatchers.containsString; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext1.Ext1; +import com.alibaba.dubbo.common.extensionloader.ext1.impl.Ext1Impl1; +import com.alibaba.dubbo.common.extensionloader.ext1.impl.Ext1Impl2; +import com.alibaba.dubbo.common.extensionloader.ext2.Ext2; +import com.alibaba.dubbo.common.extensionloader.ext2.UrlHolder; +import com.alibaba.dubbo.common.extensionloader.ext3.Ext3; +import com.alibaba.dubbo.common.extensionloader.ext4.Ext4; +import com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod; +import com.alibaba.dubbo.common.extensionloader.ext5.impl.Ext5AutoProxy1; +import com.alibaba.dubbo.common.extensionloader.ext5.impl.Ext5AutoProxy2; +import com.alibaba.dubbo.common.extensionloader.ext6_inject.Ext6; +import com.alibaba.dubbo.common.extensionloader.ext6_inject.impl.Ext6Impl2; + +/** + * @author ding.lid + */ +public class ExtensionLoaderTest { + @Test + public void test_getExtension() throws Exception { + assertTrue(ExtensionLoader.getExtensionLoader(Ext1.class).getExtension("impl1") instanceof Ext1Impl1); + assertTrue(ExtensionLoader.getExtensionLoader(Ext1.class).getExtension("impl2") instanceof Ext1Impl2); + } + + @Test + public void test_getExtension_WithAutoProxy() throws Exception { + Ext5NoAdaptiveMethod impl1 = ExtensionLoader.getExtensionLoader(Ext5NoAdaptiveMethod.class).getExtension("impl1"); + assertThat(impl1, anyOf(instanceOf(Ext5AutoProxy1.class), instanceOf(Ext5AutoProxy2.class))); + + Ext5NoAdaptiveMethod impl2 = ExtensionLoader.getExtensionLoader(Ext5NoAdaptiveMethod.class).getExtension("impl2") ; + assertThat(impl2, anyOf(instanceOf(Ext5AutoProxy1.class), instanceOf(Ext5AutoProxy2.class))); + + + URL url = new URL("p1", "1.2.3.4", 1010, "path1"); + int echoCount1 = Ext5AutoProxy1.echoCount.get(); + int echoCount2 = Ext5AutoProxy2.echoCount.get(); + int yellCount1 = Ext5AutoProxy1.yellCount.get(); + int yellCount2 = Ext5AutoProxy2.yellCount.get(); + + assertEquals("Ext5Impl1-echo", impl1.echo(url, "ha")); + assertEquals(echoCount1 + 1, Ext5AutoProxy1.echoCount.get()); + assertEquals(echoCount2 + 1, Ext5AutoProxy2.echoCount.get()); + assertEquals(yellCount1, Ext5AutoProxy1.yellCount.get()); + assertEquals(yellCount2, Ext5AutoProxy2.yellCount.get()); + + assertEquals("Ext5Impl2-yell", impl2.yell(url, "ha")); + assertEquals(echoCount1 + 1, Ext5AutoProxy1.echoCount.get()); + assertEquals(echoCount2 + 1, Ext5AutoProxy2.echoCount.get()); + assertEquals(yellCount1 + 1, Ext5AutoProxy1.yellCount.get()); + assertEquals(yellCount2 + 1, Ext5AutoProxy2.yellCount.get()); + } + + @Test + public void test_getExtension_ExceptionNoExtension() throws Exception { + try { + ExtensionLoader.getExtensionLoader(Ext1.class).getExtension("XXX"); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("No such extension com.alibaba.dubbo.common.extensionloader.ext1.Ext1 by name XXX")); + } + } + + @Test + public void test_getExtension_ExceptionNoExtension_NameOnAutoProxyNoAffact() throws Exception { + try { + ExtensionLoader.getExtensionLoader(Ext5NoAdaptiveMethod.class).getExtension("XXX"); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("No such extension com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod by name XXX")); + } + } + + @Test + public void test_getExtension_ExceptionNullArg() throws Exception { + try { + ExtensionLoader.getExtensionLoader(Ext1.class).getExtension(null); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), containsString("Extension name == null")); + } + } + + @Test + public void test_hasExtension() throws Exception { + assertTrue(ExtensionLoader.getExtensionLoader(Ext1.class).hasExtension("impl1")); + assertFalse(ExtensionLoader.getExtensionLoader(Ext1.class).hasExtension("impl1,impl2")); + assertFalse(ExtensionLoader.getExtensionLoader(Ext1.class).hasExtension("xxx")); + + try { + ExtensionLoader.getExtensionLoader(Ext1.class).hasExtension(null); + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), containsString("Extension name == null")); + } + } + + @Test + public void test_getSupportedExtensions() throws Exception { + Set exts = ExtensionLoader.getExtensionLoader(Ext1.class).getSupportedExtensions(); + + Set expected = new HashSet(); + expected.add("impl1"); + expected.add("impl2"); + expected.add("impl3"); + + assertEquals(expected, exts); + } + + @Test + public void test_getSupportedExtensions_NoExtension() throws Exception { + Set exts = ExtensionLoader.getExtensionLoader(ExtensionLoaderTest.class).getSupportedExtensions(); + assertEquals(0, exts.size()); + } + + @Test + public void test_getAdaptiveExtension_defaultExtension() throws Exception { + Ext1 ext = ExtensionLoader.getExtensionLoader(Ext1.class).getAdaptiveExtension(); + + Map map = new HashMap(); + URL url = new URL("p1", "1.2.3.4", 1010, "path1", map); + + String echo = ext.echo(url, "haha"); + assertEquals("Ext1Impl1-echo", echo); + } + + @Test + public void test_getAdaptiveExtension() throws Exception { + Ext1 ext = ExtensionLoader.getExtensionLoader(Ext1.class).getAdaptiveExtension(); + + Map map = new HashMap(); + map.put("ext1", "impl2"); + URL url = new URL("p1", "1.2.3.4", 1010, "path1", map); + + String echo = ext.echo(url, "haha"); + assertEquals("Ext1Impl2-echo", echo); + } + + @Test + public void test_getAdaptiveExtension_customizeKey() throws Exception { + Ext1 ext = ExtensionLoader.getExtensionLoader(Ext1.class).getAdaptiveExtension(); + + Map map = new HashMap(); + map.put("key2", "impl2"); + URL url = new URL("p1", "1.2.3.4", 1010, "path1", map); + + String echo = ext.yell(url, "haha"); + assertEquals("Ext1Impl2-yell", echo); + + url = url.addParameter("key1", "impl3"); // 注意: URL是值类型 + echo = ext.yell(url, "haha"); + assertEquals("Ext1Impl3-yell", echo); + } + + @Test + public void test_getAdaptiveExtension_UrlNpe() throws Exception { + Ext1 ext = ExtensionLoader.getExtensionLoader(Ext1.class).getAdaptiveExtension(); + + try { + ext.echo(null, "haha"); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("url == null", e.getMessage()); + } + } + + @Test + public void test_getAdaptiveExtension_ExceptionWhenNotAdativeMethod() throws Exception { + Ext1 ext = ExtensionLoader.getExtensionLoader(Ext1.class).getAdaptiveExtension(); + + Map map = new HashMap(); + URL url = new URL("p1", "1.2.3.4", 1010, "path1", map); + + try { + ext.bang(url, 33); + fail(); + } catch (UnsupportedOperationException expected) { + assertThat(expected.getMessage(), containsString("method ")); + assertThat( + expected.getMessage(), + containsString("of interface com.alibaba.dubbo.common.extensionloader.ext1.Ext1 is not adaptive method!")); + } + } + + @Test + public void test_getAdaptiveExtension_ExceptionWhenNoUrlAttrib() throws Exception { + try { + ExtensionLoader.getExtensionLoader(Ext4.class).getAdaptiveExtension(); + fail(); + } catch (Exception expected) { + assertThat(expected.getMessage(), containsString("fail to create adative class for interface ")); + assertThat(expected.getMessage(), containsString(": not found url parameter or url attribute in parameters of method ")); + } + } + + @Test + public void test_getAdaptiveExtension_protocolKey() throws Exception { + Ext3 ext = ExtensionLoader.getExtensionLoader(Ext3.class).getAdaptiveExtension(); + + Map map = new HashMap(); + URL url = new URL("impl3", "1.2.3.4", 1010, "path1", map); + + String echo = ext.echo(url, "s"); + assertEquals("Ext3Impl3-echo", echo); + + url = url.addParameter("key1", "impl2"); + echo = ext.echo(url, "s"); + assertEquals("Ext3Impl2-echo", echo); + + String yell = ext.yell(url, "d"); + assertEquals("Ext3Impl3-yell", yell); + } + + + @Test + public void test_getAdaptiveExtension_lastProtocolKey() throws Exception { + Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension(); + + Map map = new HashMap(); + URL url = new URL("impl1", "1.2.3.4", 1010, "path1", map); + String yell = ext.yell(url, "s"); + assertEquals("Ext2Impl1-yell", yell); + + url = url.addParameter("key1", "impl2"); + yell = ext.yell(url, "s"); + assertEquals("Ext2Impl2-yell", yell); + } + + @Test + public void test_urlHolder_getAdaptiveExtension() throws Exception { + Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension(); + + Map map = new HashMap(); + map.put("ext2", "impl1"); + URL url = new URL("p1", "1.2.3.4", 1010, "path1", map); + + UrlHolder holder = new UrlHolder(); + holder.setUrl(url); + + String echo = ext.echo(holder, "haha"); + assertEquals("Ext2Impl1-echo", echo); + } + + @Test + public void test_urlHolder_getAdaptiveExtension_noExtension() throws Exception { + Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension(); + + URL url = new URL("p1", "1.2.3.4", 1010, "path1"); + + UrlHolder holder = new UrlHolder(); + holder.setUrl(url); + + try { + ext.echo(holder, "haha"); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Fail to get extension(")); + } + + url = url.addParameter("ext2", "XXX"); + holder.setUrl(url); + try { + ext.echo(holder, "haha"); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("No such extension")); + } + } + + @Test + public void test_urlHolder_getAdaptiveExtension_UrlNpe() throws Exception { + Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension(); + + try { + ext.echo(null, "haha"); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("com.alibaba.dubbo.common.extensionloader.ext2.UrlHolder argument == null", e.getMessage()); + } + + try { + ext.echo(new UrlHolder(), "haha"); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("com.alibaba.dubbo.common.extensionloader.ext2.UrlHolder argument getUrl() == null", e.getMessage()); + } + } + + @Test + public void test_urlHolder_getAdaptiveExtension_ExceptionWhenNotAdativeMethod() throws Exception { + Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension(); + + Map map = new HashMap(); + URL url = new URL("p1", "1.2.3.4", 1010, "path1", map); + + try { + ext.bang(url, 33); + fail(); + } catch (UnsupportedOperationException expected) { + assertThat(expected.getMessage(), containsString("method ")); + assertThat( + expected.getMessage(), + containsString("of interface com.alibaba.dubbo.common.extensionloader.ext2.Ext2 is not adaptive method!")); + } + } + + @Test + public void test_urlHolder_getAdaptiveExtension_ExceptionWhenNameNotProvided() throws Exception { + Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension(); + + URL url = new URL("p1", "1.2.3.4", 1010, "path1"); + + UrlHolder holder = new UrlHolder(); + holder.setUrl(url); + + try { + ext.echo(holder, "impl1"); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Fail to get extension(")); + } + + url = url.addParameter("key1", "impl1"); + holder.setUrl(url); + try { + ext.echo(holder, "haha"); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext2.Ext2) name from url")); + } + } + + @Test + public void test_getAdaptiveExtension_inject() throws Exception { + Ext6 ext = ExtensionLoader.getExtensionLoader(Ext6.class).getAdaptiveExtension(); + + URL url = new URL("p1", "1.2.3.4", 1010, "path1"); + url = url.addParameters("ext6", "impl1"); + + assertEquals("Ext6Impl1-echo-Ext1Impl1-echo", ext.echo(url, "ha")); + + url = url.addParameters("ext1", "impl2"); + assertEquals("Ext6Impl1-echo-Ext1Impl2-echo", ext.echo(url, "ha")); + } + + @Test + public void test_getAdaptiveExtension_InjectNotExtFail() throws Exception { + Ext6 ext = ExtensionLoader.getExtensionLoader(Ext6.class).getExtension("impl2"); + + Ext6Impl2 impl = (Ext6Impl2) ext; + assertNull(impl.getList()); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/Ext1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/Ext1.java new file mode 100644 index 0000000000..8f5ed51989 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/Ext1.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext1; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * @author ding.lid + */ +@Extension("impl1") +public interface Ext1 { + @Adaptive + String echo(URL url, String s); + + @Adaptive({"key1", "key2"}) + String yell(URL url, String s); + + String bang(URL url, int i); +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl1.java new file mode 100644 index 0000000000..9572b2653b --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl1.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext1.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext1.Ext1; + +/** + * @author ding.lid + */ +@Extension(value = "impl1") +public class Ext1Impl1 implements Ext1 { + public String echo(URL url, String s) { + return "Ext1Impl1-echo"; + } + + public String yell(URL url, String s) { + return "Ext1Impl1-yell"; + } + + public String bang(URL url, int i) { + return "bang1"; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl2.java new file mode 100644 index 0000000000..04b169a047 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl2.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext1.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext1.Ext1; + +/** + * @author ding.lid + * + */ +@Extension("impl2") +public class Ext1Impl2 implements Ext1 { + public String echo(URL url, String s) { + return "Ext1Impl2-echo"; + } + + public String yell(URL url, String s) { + return "Ext1Impl2-yell"; + } + + public String bang(URL url, int i) { + return "bang2"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl3.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl3.java new file mode 100644 index 0000000000..b702bbb20e --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext1/impl/Ext1Impl3.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext1.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext1.Ext1; + +/** + * @author ding.lid + * + */ +@Extension("impl3") +public class Ext1Impl3 implements Ext1 { + public String echo(URL url, String s) { + return "Ext1Impl3-echo"; + } + + public String yell(URL url, String s) { + return "Ext1Impl3-yell"; + } + + public String bang(URL url, int i) { + return "bang3"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/Ext2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/Ext2.java new file mode 100644 index 0000000000..5877c3035b --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/Ext2.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext2; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.URL; + +/** + * 无Default + * + * @author ding.lid + */ +public interface Ext2 { + @Adaptive + String echo(UrlHolder holder, String s); + + @Adaptive({"key1", "protocol"}) + String yell(URL url, String s); + + String bang(URL url, int i); +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/UrlHolder.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/UrlHolder.java new file mode 100644 index 0000000000..c959315862 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/UrlHolder.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext2; + +import com.alibaba.dubbo.common.URL; + +/** + * @author ding.lid + * + */ +public class UrlHolder { + private Double Num; + + private URL url; + + private String name; + + private int age; + + public Double getNum() { + return Num; + } + + public void setNum(Double num) { + Num = num; + } + + public URL getUrl() { + return url; + } + + public void setUrl(URL url) { + this.url = url; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl1.java new file mode 100644 index 0000000000..0612d1b5af --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl1.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext2.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext2.Ext2; +import com.alibaba.dubbo.common.extensionloader.ext2.UrlHolder; + +/** + * @author ding.lid + */ +@Extension(value = "impl1") +public class Ext2Impl1 implements Ext2 { + public String echo(UrlHolder holder, String s) { + return "Ext2Impl1-echo"; + } + + public String yell(URL url, String s) { + return "Ext2Impl1-yell"; + } + + public String bang(URL url, int i) { + return "bang1"; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl2.java new file mode 100644 index 0000000000..75af3c8160 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl2.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext2.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext2.Ext2; +import com.alibaba.dubbo.common.extensionloader.ext2.UrlHolder; + +/** + * @author ding.lid + * + */ +@Extension("impl2") +public class Ext2Impl2 implements Ext2 { + public String echo(UrlHolder holder, String s) { + return "Ext2Impl2-echo"; + } + + public String yell(URL url, String s) { + return "Ext2Impl2-yell"; + } + + public String bang(URL url, int i) { + return "bang2"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl3.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl3.java new file mode 100644 index 0000000000..4b1ca59105 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext2/impl/Ext2Impl3.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext2.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext2.Ext2; +import com.alibaba.dubbo.common.extensionloader.ext2.UrlHolder; + +/** + * @author ding.lid + * + */ +@Extension("impl3") +public class Ext2Impl3 implements Ext2 { + public String echo(UrlHolder holder, String s) { + return "Ext2Impl3-echo"; + } + + public String yell(URL url, String s) { + return "Ext2Impl3-yell"; + } + + public String bang(URL url, int i) { + return "bang3"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/Ext3.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/Ext3.java new file mode 100644 index 0000000000..f043b983c7 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/Ext3.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext3; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * @author ding.lid + */ +@Extension("impl3") +public interface Ext3 { + @Adaptive({"key1", "protocol"}) + String echo(URL url, String s); + + @Adaptive({"protocol", "key2"}) + String yell(URL url, String s); + + String bang(URL url, int i); +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl1.java new file mode 100644 index 0000000000..eabc87577e --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl1.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext3.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext3.Ext3; + +/** + * @author ding.lid + */ +@Extension(value = "impl1") +public class Ext3Impl1 implements Ext3 { + public String echo(URL url, String s) { + return "Ext3Impl3-echo"; + } + + public String yell(URL url, String s) { + return "Ext3Impl3-yell"; + } + + public String bang(URL url, int i) { + return "bang1"; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl2.java new file mode 100644 index 0000000000..462474bd5c --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl2.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext3.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext3.Ext3; + +/** + * @author ding.lid + * + */ +@Extension("impl2") +public class Ext3Impl2 implements Ext3 { + public String echo(URL url, String s) { + return "Ext3Impl2-echo"; + } + + public String yell(URL url, String s) { + return "Ext3Impl2-yell"; + } + + public String bang(URL url, int i) { + return "bang2"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl3.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl3.java new file mode 100644 index 0000000000..e549455989 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext3/impl/Ext3Impl3.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext3.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext3.Ext3; + +/** + * @author ding.lid + * + */ +@Extension(value="impl3") +public class Ext3Impl3 implements Ext3 { + public String echo(URL url, String s) { + return "Ext3Impl3-echo"; + } + + public String yell(URL url, String s) { + return "Ext3Impl3-yell"; + } + + public String bang(URL url, int i) { + return "bang3"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/Ext4.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/Ext4.java new file mode 100644 index 0000000000..19978f65af --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/Ext4.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext4; + +import java.util.List; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; + +/** + * @author ding.lid + */ +@Extension("impl1") +public interface Ext4 { + @Adaptive + String bark(String name, List list); // 没有URL参数的方法 +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/impl/Ext4Impl1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/impl/Ext4Impl1.java new file mode 100644 index 0000000000..98201d3b0f --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/impl/Ext4Impl1.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext4.impl; + +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.extensionloader.ext4.Ext4; + +/** + * @author ding.lid + */ +@Extension(value = "impl1") +public class Ext4Impl1 implements Ext4 { + public String bark(String name, List list) { + return null; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/impl/Ext4Impl2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/impl/Ext4Impl2.java new file mode 100644 index 0000000000..cdaca9fe62 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext4/impl/Ext4Impl2.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext4.impl; + +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext4.Ext4; + +/** + * @author ding.lid + * + */ +@Extension("impl2") +public class Ext4Impl2 implements Ext4 { + public String echo(URL url, String s) { + return "Ext3Impl2-echo"; + } + + public String yell(URL url, String s) { + return "Ext3Impl2-yell"; + } + + public String bang(URL url, int i) { + return "bang2"; + } + + public String bark(String name, List list) { + return null; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/Ext5NoAdaptiveMethod.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/Ext5NoAdaptiveMethod.java new file mode 100644 index 0000000000..3c2ae8a565 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/Ext5NoAdaptiveMethod.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext5; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * @author ding.lid + */ +@Extension("impl1") +public interface Ext5NoAdaptiveMethod { + String echo(URL url, String s); + + String yell(URL url, String s); + + String bang(URL url, int i); +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5AutoProxy1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5AutoProxy1.java new file mode 100644 index 0000000000..ebc05b9271 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5AutoProxy1.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext5.impl; + +import java.util.concurrent.atomic.AtomicInteger; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod; + +/** + * @author ding.lid + */ +@Extension("XXX") +public class Ext5AutoProxy1 implements Ext5NoAdaptiveMethod { + Ext5NoAdaptiveMethod instance; + + public static AtomicInteger echoCount = new AtomicInteger(); + public static AtomicInteger yellCount = new AtomicInteger(); + public static AtomicInteger bangCount = new AtomicInteger(); + + public Ext5AutoProxy1(Ext5NoAdaptiveMethod instance) { + this.instance = instance; + } + + public String echo(URL url, String s) { + echoCount.incrementAndGet(); + return instance.echo(url, s); + } + + public String yell(URL url, String s) { + yellCount.incrementAndGet(); + return instance.yell(url, s); + } + + public String bang(URL url, int i) { + bangCount.incrementAndGet(); + return instance.bang(url, i); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5AutoProxy2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5AutoProxy2.java new file mode 100644 index 0000000000..a5f3d30fb2 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5AutoProxy2.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext5.impl; + +import java.util.concurrent.atomic.AtomicInteger; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod; + +/** + * @author ding.lid + */ +public class Ext5AutoProxy2 implements Ext5NoAdaptiveMethod { + Ext5NoAdaptiveMethod instance; + + public static AtomicInteger echoCount = new AtomicInteger(); + public static AtomicInteger yellCount = new AtomicInteger(); + public static AtomicInteger bangCount = new AtomicInteger(); + + public Ext5AutoProxy2(Ext5NoAdaptiveMethod instance) { + this.instance = instance; + } + + public String echo(URL url, String s) { + echoCount.incrementAndGet(); + return instance.echo(url, s); + } + + public String yell(URL url, String s) { + yellCount.incrementAndGet(); + return instance.yell(url, s); + } + + public String bang(URL url, int i) { + bangCount.incrementAndGet(); + return instance.bang(url, i); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5Impl1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5Impl1.java new file mode 100644 index 0000000000..8076e60293 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5Impl1.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext5.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod; + +/** + * @author ding.lid + */ +@Extension("impl1") +public class Ext5Impl1 implements Ext5NoAdaptiveMethod { + public String echo(URL url, String s) { + return "Ext5Impl1-echo"; + } + + public String yell(URL url, String s) { + return "Ext5Impl1-yell"; + } + + public String bang(URL url, int i) { + return "impl1"; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5Impl2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5Impl2.java new file mode 100644 index 0000000000..073de1956c --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext5/impl/Ext5Impl2.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext5.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod; + +/** + * @author ding.lid + * + */ +@Extension("impl2") +public class Ext5Impl2 implements Ext5NoAdaptiveMethod { + public String echo(URL url, String s) { + return "Ext5Impl2-echo"; + } + + public String yell(URL url, String s) { + return "Ext5Impl2-yell"; + } + + public String bang(URL url, int i) { + return "impl2"; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/Ext6.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/Ext6.java new file mode 100644 index 0000000000..72dd49e9e2 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/Ext6.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext6_inject; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * 无Default + * + * @author ding.lid + */ +@Extension +public interface Ext6 { + @Adaptive + String echo(URL url, String s); +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/impl/Ext6Impl1.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/impl/Ext6Impl1.java new file mode 100644 index 0000000000..3396331988 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/impl/Ext6Impl1.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext6_inject.impl; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext1.Ext1; +import com.alibaba.dubbo.common.extensionloader.ext6_inject.Ext6; + +/** + * @author ding.lid + */ +@Extension(value = "impl1") +public class Ext6Impl1 implements Ext6 { + Ext1 ext1; + + public void setExt1(Ext1 ext1) { + this.ext1 = ext1; + } + + public String echo(URL url, String s) { + return "Ext6Impl1-echo-" + ext1.echo(url, s); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/impl/Ext6Impl2.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/impl/Ext6Impl2.java new file mode 100644 index 0000000000..3161cf9ef9 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/extensionloader/ext6_inject/impl/Ext6Impl2.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.extensionloader.ext6_inject.impl; + +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extensionloader.ext6_inject.Ext6; + +/** + * @author ding.lid + */ +@Extension("impl2") +public class Ext6Impl2 implements Ext6 { + List list; + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public String echo(URL url, String s) { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/io/BytesTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/io/BytesTest.java new file mode 100644 index 0000000000..8e6c97df3e --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/io/BytesTest.java @@ -0,0 +1,122 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import org.junit.Assert; + +import junit.framework.TestCase; + +public class BytesTest extends TestCase +{ + private static final byte[] b1 = "adpfioha;eoh;aldfadl;kfadslkfdajfio123431241235123davas;odvwe;lmzcoqpwoewqogineopwqihwqetup\n\tejqf;lajsfd中文字符0da0gsaofdsf==adfasdfs".getBytes(); + + public void testMain() throws Exception + { + short s = (short)0xabcd; + assertEquals(s, Bytes.bytes2short(Bytes.short2bytes(s)) ); + + int i = 198284; + assertEquals(i, Bytes.bytes2int(Bytes.int2bytes(i)) ); + + long l = 13841747174l; + assertEquals(l, Bytes.bytes2long(Bytes.long2bytes(l)) ); + + float f = 1.3f; + assertEquals(f, Bytes.bytes2float(Bytes.float2bytes(f)) ); + + double d = 11213.3; + assertEquals(d, Bytes.bytes2double(Bytes.double2bytes(d)) ); + + assertSame(Bytes.int2bytes(i), int2bytes(i)); + assertSame(Bytes.long2bytes(l), long2bytes(l)); + } + + public void testBase64() throws Exception + { + String str = Bytes.bytes2base64(b1); + byte[] b2 = Bytes.base642bytes(str); + assertSame(b1, b2); + } + + static byte[] bytes1 = {3,12,14,41,12,2,3,12,4,67,23}; + static byte[] bytes2 = {3,12,14,41,12,2,3,12,4,67}; + // 把失败的情况,失败Case加的防护网: + // 当有填充字符时,会失败! + public void testBase64_s2b2s_FailCaseLog() throws Exception { + String s1 = Bytes.bytes2base64(bytes1); + byte[] out1 = Bytes.base642bytes(s1); + Assert.assertArrayEquals(bytes1, out1); + + + String s2 = Bytes.bytes2base64(bytes2); + byte[] out2 = Bytes.base642bytes(s2); + Assert.assertArrayEquals(bytes2, out2); + } + + public void testHex() throws Exception + { + String str = Bytes.bytes2hex(b1); + assertSame(b1, Bytes.hex2bytes(str)); + } + + private static void assertSame(byte[] b1, byte[] b2) + { + assertEquals(b1.length, b2.length); + for(int i=0;i> 24); + bb[1] = (byte) (x >> 16); + bb[2] = (byte) (x >> 8); + bb[3] = (byte) (x >> 0); + return bb; + } + + static public int bytes2int(byte[] bb, int idx) { + return ((bb[idx + 0] & 0xFF) << 24) + | ((bb[idx + 1] & 0xFF) << 16) + | ((bb[idx + 2] & 0xFF) << 8) + | ((bb[idx + 3] & 0xFF) << 0); + } + + static public byte[] long2bytes(long x) { + byte[] bb = new byte[8]; + bb[0] = (byte) (x >> 56); + bb[1] = (byte) (x >> 48); + bb[2] = (byte) (x >> 40); + bb[3] = (byte) (x >> 32); + bb[4] = (byte) (x >> 24); + bb[5] = (byte) (x >> 16); + bb[6] = (byte) (x >> 8); + bb[7] = (byte) (x >> 0); + return bb; + } + + static public long bytes2long(byte[] bb, int idx) { + return (((long) bb[idx + 0] & 0xFF) << 56) + | (((long) bb[idx + 1] & 0xFF) << 48) + | (((long) bb[idx + 2] & 0xFF) << 40) + | (((long) bb[idx + 3] & 0xFF) << 32) + | (((long) bb[idx + 4] & 0xFF) << 24) + | (((long) bb[idx + 5] & 0xFF) << 16) + | (((long) bb[idx + 6] & 0xFF) << 8) + | (((long) bb[idx + 7] & 0xFF) << 0); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/io/StreamUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/io/StreamUtilsTest.java new file mode 100644 index 0000000000..17bbc7c499 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/io/StreamUtilsTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.io; + +import java.io.InputStream; +import java.io.PushbackInputStream; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author ding.lid + */ +public class StreamUtilsTest { + + @Test + public void testMarkSupportedInputStream() throws Exception { + InputStream is = StreamUtilsTest.class.getResourceAsStream("/StreamUtilsTest.txt"); + assertEquals(10, is.available()); + + is = new PushbackInputStream(is); + assertEquals(10, is.available()); + assertFalse(is.markSupported()); + + is = StreamUtils.markSupportedInputStream(is); + assertEquals(10, is.available()); + + is.mark(0); + assertEquals((int) '0', is.read()); + assertEquals((int) '1', is.read()); + + is.reset(); + assertEquals((int) '0', is.read()); + assertEquals((int) '1', is.read()); + assertEquals((int) '2', is.read()); + + is.mark(0); + assertEquals((int) '3', is.read()); + assertEquals((int) '4', is.read()); + assertEquals((int) '5', is.read()); + + is.reset(); + assertEquals((int) '3', is.read()); + assertEquals((int) '4', is.read()); + + is.mark(0); + assertEquals((int) '5', is.read()); + assertEquals((int) '6', is.read()); + + is.reset(); + assertEquals((int) '5', is.read()); + assertEquals((int) '6', is.read()); + assertEquals((int) '7', is.read()); + assertEquals((int) '8', is.read()); + assertEquals((int) '9', is.read()); + assertEquals(-1, is.read()); + assertEquals(-1, is.read()); + + is.mark(0); + assertEquals(-1, is.read()); + assertEquals(-1, is.read()); + + is.reset(); + assertEquals(-1, is.read()); + assertEquals(-1, is.read()); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONReaderTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONReaderTest.java new file mode 100644 index 0000000000..b3330d6d8a --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONReaderTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import com.alibaba.dubbo.common.io.UnsafeStringReader; + +import junit.framework.TestCase; + +public class JSONReaderTest extends TestCase +{ + public void testMain() throws Exception + { + String json = "{ name: 'name', friends: [ 1, null, 3.2, ] }"; + JSONReader reader = new JSONReader(new UnsafeStringReader(json)); + assertEquals(reader.nextToken().type, JSONToken.LBRACE); + assertEquals(reader.nextToken().type, JSONToken.IDENT); + assertEquals(reader.nextToken().type, JSONToken.COLON); + assertEquals(reader.nextToken().type, JSONToken.STRING); + assertEquals(reader.nextToken().type, JSONToken.COMMA); + assertEquals(reader.nextToken().type, JSONToken.IDENT); + assertEquals(reader.nextToken().type, JSONToken.COLON); + assertEquals(reader.nextToken().type, JSONToken.LSQUARE); + assertEquals(reader.nextToken().type, JSONToken.INT); + assertEquals(reader.nextToken().type, JSONToken.COMMA); + assertEquals(reader.nextToken().type, JSONToken.NULL); + assertEquals(reader.nextToken().type, JSONToken.COMMA); + assertEquals(reader.nextToken().type, JSONToken.FLOAT); + assertEquals(reader.nextToken().type, JSONToken.COMMA); + assertEquals(reader.nextToken().type, JSONToken.RSQUARE); + assertEquals(reader.nextToken().type, JSONToken.RBRACE); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java new file mode 100644 index 0000000000..337dba73d9 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONTest.java @@ -0,0 +1,217 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.StringReader; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import junit.framework.Assert; +import junit.framework.TestCase; + +public class JSONTest extends TestCase +{ + public void testException() throws Exception { + MyException e = new MyException("001", "AAAAAAAA"); + + StringWriter writer = new StringWriter(); + JSON.json(e, writer); + String json = writer.getBuffer().toString(); + System.out.println(json); + // Assert.assertEquals("{\"code\":\"001\",\"message\":\"AAAAAAAA\"}", json); + + StringReader reader = new StringReader(json); + MyException result = JSON.parse(reader, MyException.class); + Assert.assertEquals("001", result.getCode()); + Assert.assertEquals("AAAAAAAA", result.getMessage()); + } + + @SuppressWarnings("unchecked") + public void testMap() throws Exception { + Map map = new HashMap(); + map.put("aaa", "bbb"); + + StringWriter writer = new StringWriter(); + JSON.json(map, writer); + String json = writer.getBuffer().toString(); + Assert.assertEquals("{\"aaa\":\"bbb\"}", json); + + StringReader reader = new StringReader(json); + Map result = JSON.parse(reader, Map.class); + Assert.assertEquals("bbb", result.get("aaa")); + } + + @SuppressWarnings("unchecked") + public void testMapArray() throws Exception { + Map map = new HashMap(); + map.put("aaa", "bbb"); + + StringWriter writer = new StringWriter(); + JSON.json(new Object[] {map}, writer); // args + String json = writer.getBuffer().toString(); + Assert.assertEquals("[{\"aaa\":\"bbb\"}]", json); + + StringReader reader = new StringReader(json); + Object[] result = JSON.parse(reader, new Class[] { Map.class }); + Assert.assertEquals(1, result.length); + Assert.assertEquals("bbb", ((Map)result[0]).get("aaa")); + } + + @SuppressWarnings("unchecked") + public void testLinkedMap() throws Exception { + LinkedHashMap map = new LinkedHashMap(); + map.put("aaa", "bbb"); + + StringWriter writer = new StringWriter(); + JSON.json(map, writer); + String json = writer.getBuffer().toString(); + Assert.assertEquals("{\"aaa\":\"bbb\"}", json); + + StringReader reader = new StringReader(json); + LinkedHashMap result = JSON.parse(reader, LinkedHashMap.class); + Assert.assertEquals("bbb", result.get("aaa")); + } + + public void testObject2Json() throws Exception + { + Bean bean = new Bean(); + bean.array = new int[]{1, 3, 4}; + bean.setName("ql"); + + String json = JSON.json(bean); + bean = JSON.parse(json, Bean.class); + assertEquals(bean.getName(), "ql"); + assertEquals(bean.getDisplayName(), "钱磊"); + assertEquals(bean.bytes.length, DEFAULT_BYTES.length); + assertEquals(bean.$$, DEFAULT_$$); + + assertEquals("{\"name\":\"ql\",\"array\":[1,3,4]}", JSON.json(bean, new String[]{"name", "array"})); + } + + public void testParse2JSONObject() throws Exception + { + JSONObject jo = (JSONObject)JSON.parse("{name:'qianlei',array:[1,2,3,4,98.123],b1:TRUE,$1:NULL,$2:FALSE,__3:NULL}"); + assertEquals(jo.getString("name"), "qianlei"); + assertEquals(jo.getArray("array").length(), 5); + assertEquals(jo.get("$2"), Boolean.FALSE); + assertEquals(jo.get("__3"), null); + + for(int i=0;i<10000;i++) + JSON.parse("{\"name\":\"qianlei\",\"array\":[1,2,3,4,98.123],\"displayName\":\"钱磊\"}"); + + long now = System.currentTimeMillis(); + for(int i=0;i<10000;i++) + JSON.parse("{\"name\":\"qianlei\",\"array\":[1,2,3,4,98.123],\"displayName\":\"钱磊\"}"); + System.out.println("parse to JSONObject 10000 times in: " + ( System.currentTimeMillis()-now) ); + } + + @SuppressWarnings("unchecked") + public void testParse2Class() throws Exception + { + int[] o1 = {1,2,3,4,5}, o2 = JSON.parse("[1.2,2,3,4,5]", int[].class); + assertEquals(o2.length, 5); + for(int i=0;i<5;i++) + assertEquals(o1[i], o2[i]); + + List l1 = (List)JSON.parse("[1.2,2,3,4,5]", List.class); + assertEquals(l1.size(), 5); + for(int i=0;i<5;i++) + assertEquals(o1[i], ((Number)l1.get(i)).intValue()); + + Bean bean = JSON.parse("{name:'qianlei',array:[1,2,3,4,98.123],displayName:'钱磊',$$:214726,$b:TRUE}", Bean.class); + assertEquals(bean.getName(), "qianlei"); + assertEquals(bean.getDisplayName(), "钱磊"); + assertEquals(bean.array.length, 5); + assertEquals(bean.$$, 214726); + assertEquals(bean.$b, true); + + for(int i=0;i<10000;i++) + JSON.parse("{name:'qianlei',array:[1,2,3,4,98.123],displayName:'钱磊'}", Bean1.class); + + long now = System.currentTimeMillis(); + for(int i=0;i<10000;i++) + JSON.parse("{name:'qianlei',array:[1,2,3,4,98.123],displayName:'钱磊'}", Bean1.class); + System.out.println("parse to Class 10000 times in: " + ( System.currentTimeMillis()-now) ); + } + + public void testParse2Arguments() throws Exception + { + Object[] test = JSON.parse("[1.2, 2, {name:'qianlei',array:[1,2,3,4,98.123]} ]", new Class[]{ int.class, int.class, Bean.class }); + assertEquals(test[1], 2); + assertEquals(test[2].getClass(), Bean.class); + test = JSON.parse("[1.2, 2]", new Class[]{ int.class, int.class }); + assertEquals(test[0], 1); + } + + static byte[] DEFAULT_BYTES = {3,12,14,41,12,2,3,12,4,67,23}; + + static int DEFAULT_$$ = 152; + + public static class Bean1 + { + private String name,displayName; + + public int[] array; + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class Bean + { + private String name, displayName = "钱磊"; + + public int[] array; + + public boolean $b; + + public int $$ = DEFAULT_$$; + + public byte[] bytes = DEFAULT_BYTES; + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONWriterTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONWriterTest.java new file mode 100644 index 0000000000..16a71e859e --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/JSONWriterTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +import java.io.StringWriter; + +import junit.framework.TestCase; + +public class JSONWriterTest extends TestCase +{ + public void testWriteJson() throws Exception + { + StringWriter w = new StringWriter(); + JSONWriter writer = new JSONWriter(w); + + writer.valueNull(); + assertEquals(w.getBuffer().toString(), "null"); + + // write array. + w.getBuffer().setLength(0); + writer.arrayBegin().valueNull().valueBoolean(false).valueInt(16).arrayEnd(); + assertEquals(w.getBuffer().toString(),"[null,false,16]"); + + // write object. + w.getBuffer().setLength(0); + writer.objectBegin().objectItem("type").valueString("com.alibaba.dubbo.TestService").objectItem("version").valueString("1.1.0").objectEnd(); + assertEquals(w.getBuffer().toString(),"{\"type\":\"com.alibaba.dubbo.TestService\",\"version\":\"1.1.0\"}"); + + w.getBuffer().setLength(0); + writer.objectBegin(); + writer.objectItem("name").objectItem("displayName"); + writer.objectItem("emptyList").arrayBegin().arrayEnd(); + writer.objectItem("list").arrayBegin().valueNull().valueBoolean(false).valueInt(16).valueString("stri'''ng").arrayEnd(); + writer.objectItem("service").objectBegin().objectItem("type").valueString("com.alibaba.dubbo.TestService").objectItem("version").valueString("1.1.0").objectEnd(); + writer.objectEnd(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/MyException.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/MyException.java new file mode 100644 index 0000000000..178916d15b --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/json/MyException.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.json; + +public class MyException extends Exception { + + private static final long serialVersionUID = 2905707783883694687L; + + private String code; + + public MyException() { + } + + public MyException(String code, String message) { + super(message); + this.code = code; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/AnimalEnum.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/AnimalEnum.java new file mode 100644 index 0000000000..63299676f1 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/AnimalEnum.java @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model; + +/** + * @author ding.lid + * + */ +public enum AnimalEnum { + dog, cat, rat, cow, bull, horse; +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/BizException.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/BizException.java new file mode 100644 index 0000000000..5b8643ae0f --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/BizException.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model; + +public class BizException extends RuntimeException{ + + private static final long serialVersionUID = 1L; + + public BizException(String message){ + super(message); + } + + public BizException() { + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/BizExceptionNoDefaultConstructor.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/BizExceptionNoDefaultConstructor.java new file mode 100644 index 0000000000..71f257f7be --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/BizExceptionNoDefaultConstructor.java @@ -0,0 +1,25 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model; + +public class BizExceptionNoDefaultConstructor extends RuntimeException{ + + private static final long serialVersionUID = 1L; + + public BizExceptionNoDefaultConstructor(String message){ + super(message); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/Person.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/Person.java new file mode 100644 index 0000000000..1e6b7c6f2d --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/Person.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model; + +import java.util.Arrays; + +/** + * @author ding.lid + */ +public class Person { + private String name = "name1"; + + byte oneByte = 123; + + private int age = 11; + + private String[] value = {"value1", "value2"}; + + public String getName() { + return name; + } + + public byte getOneByte() { + return oneByte; + } + + public void setOneByte(byte b) { + this.oneByte = b; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String[] getValue() { + return value; + } + + public void setValue(String[] value) { + this.value = value; + } + + @Override + public String toString() { + return String.format("Person name(%s) age(%d) byte(%s) [value=%s]", name, age, oneByte, Arrays.toString(value)); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + age; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + Arrays.hashCode(value); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Person other = (Person) obj; + if (age != other.age) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/SerializablePerson.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/SerializablePerson.java new file mode 100644 index 0000000000..29dd8fa5e0 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/SerializablePerson.java @@ -0,0 +1,102 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * @author ding.lid + */ +public class SerializablePerson implements Serializable { + private static final long serialVersionUID = 1L; + + private String name = "name1"; + + byte oneByte = 123; + + private int age = 11; + + private String[] value = {"value1", "value2"}; + + public String getName() { + return name; + } + + public byte getOneByte() { + return oneByte; + } + + public void setOneByte(byte b) { + this.oneByte = b; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String[] getValue() { + return value; + } + + public void setValue(String[] value) { + this.value = value; + } + + @Override + public String toString() { + return String.format("Person name(%s) age(%d) byte(%s) [value=%s]", name, age, oneByte, Arrays.toString(value)); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + age; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + Arrays.hashCode(value); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SerializablePerson other = (SerializablePerson) obj; + if (age != other.age) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/Image.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/Image.java new file mode 100644 index 0000000000..9064fb2ace --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/Image.java @@ -0,0 +1,123 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.media; + + +public class Image implements java.io.Serializable +{ + private static final long serialVersionUID = 1L; + + public enum Size { + SMALL, LARGE + } + + public String uri; + + public String title; // Can be null + public int width; + public int height; + public Size size; + + public Image() {} + + public Image (String uri, String title, int width, int height, Size size) { + this.height = height; + this.title = title; + this.uri = uri; + this.width = width; + this.size = size; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Image image = (Image) o; + + if (height != image.height) return false; + if (width != image.width) return false; + if (size != image.size) return false; + if (title != null ? !title.equals(image.title) : image.title != null) return false; + if (uri != null ? !uri.equals(image.uri) : image.uri != null) return false; + + return true; + } + + @Override + public int hashCode() + { + int result = uri != null ? uri.hashCode() : 0; + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + width; + result = 31 * result + height; + result = 31 * result + (size != null ? size.hashCode() : 0); + return result; + } + + public String toString () { + StringBuilder sb = new StringBuilder(); + sb.append("[Image "); + sb.append("uri=").append(uri); + sb.append(", title=").append(title); + sb.append(", width=").append(width); + sb.append(", height=").append(height); + sb.append(", size=").append(size); + sb.append("]"); + return sb.toString(); + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setSize(Size size) { + this.size = size; + } + + public String getUri() { + return uri; + } + + public String getTitle() { + return title; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public Size getSize() { + return size; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/Media.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/Media.java new file mode 100644 index 0000000000..1ec45f0ccb --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/Media.java @@ -0,0 +1,208 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.media; + +import java.util.List; + +@SuppressWarnings("serial") +public class Media implements java.io.Serializable { + public enum Player { + JAVA, FLASH + } + + public String uri; + public String title; // Can be unset. + public int width; + public int height; + public String format; + public long duration; + public long size; + public int bitrate; // Can be unset. + public boolean hasBitrate; + public List persons; + + public Player player; + + public String copyright; // Can be unset. + + public Media() {} + + public Media(String uri, String title, int width, int height, String format, long duration, long size, int bitrate, boolean hasBitrate, List persons, Player player, String copyright) + { + this.uri = uri; + this.title = title; + this.width = width; + this.height = height; + this.format = format; + this.duration = duration; + this.size = size; + this.bitrate = bitrate; + this.hasBitrate = hasBitrate; + this.persons = persons; + this.player = player; + this.copyright = copyright; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Media media = (Media) o; + + if (bitrate != media.bitrate) return false; + if (duration != media.duration) return false; + if (hasBitrate != media.hasBitrate) return false; + if (height != media.height) return false; + if (size != media.size) return false; + if (width != media.width) return false; + if (copyright != null ? !copyright.equals(media.copyright) : media.copyright != null) return false; + if (format != null ? !format.equals(media.format) : media.format != null) return false; + if (persons != null ? !persons.equals(media.persons) : media.persons != null) return false; + if (player != media.player) return false; + if (title != null ? !title.equals(media.title) : media.title != null) return false; + if (uri != null ? !uri.equals(media.uri) : media.uri != null) return false; + + return true; + } + + @Override + public int hashCode() + { + int result = uri != null ? uri.hashCode() : 0; + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + width; + result = 31 * result + height; + result = 31 * result + (format != null ? format.hashCode() : 0); + result = 31 * result + (int) (duration ^ (duration >>> 32)); + result = 31 * result + (int) (size ^ (size >>> 32)); + result = 31 * result + bitrate; + result = 31 * result + (hasBitrate ? 1 : 0); + result = 31 * result + (persons != null ? persons.hashCode() : 0); + result = 31 * result + (player != null ? player.hashCode() : 0); + result = 31 * result + (copyright != null ? copyright.hashCode() : 0); + return result; + } + + public String toString () { + StringBuilder sb = new StringBuilder(); + sb.append("[Media "); + sb.append("uri=").append(uri); + sb.append(", title=").append(title); + sb.append(", width=").append(width); + sb.append(", height=").append(height); + sb.append(", format=").append(format); + sb.append(", duration=").append(duration); + sb.append(", size=").append(size); + sb.append(", hasBitrate=").append(hasBitrate); + sb.append(", bitrate=").append(String.valueOf(bitrate)); + sb.append(", persons=").append(persons); + sb.append(", player=").append(player); + sb.append(", copyright=").append(copyright); + sb.append("]"); + return sb.toString(); + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setFormat(String format) { + this.format = format; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public void setSize(long size) { + this.size = size; + } + + public void setBitrate(int bitrate) { + this.bitrate = bitrate; + this.hasBitrate = true; + } + + public void setPersons(List persons) { + this.persons = persons; + } + + public void setPlayer(Player player) { + this.player = player; + } + + public void setCopyright(String copyright) { + this.copyright = copyright; + } + + public String getUri() { + return uri; + } + + public String getTitle() { + return title; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public String getFormat() { + return format; + } + + public long getDuration() { + return duration; + } + + public long getSize() { + return size; + } + + public int getBitrate() { + return bitrate; + } + + public List getPersons() { + return persons; + } + + public Player getPlayer() { + return player; + } + + public String getCopyright() { + return copyright; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/MediaContent.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/MediaContent.java new file mode 100644 index 0000000000..471dc89e77 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/media/MediaContent.java @@ -0,0 +1,79 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.media; + +import java.util.List; + +@SuppressWarnings("serial") +public class MediaContent implements java.io.Serializable +{ + public Media media; + public List images; + + public MediaContent() {} + + public MediaContent (Media media, List images) { + this.media = media; + this.images = images; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MediaContent that = (MediaContent) o; + + if (images != null ? !images.equals(that.images) : that.images != null) return false; + if (media != null ? !media.equals(that.media) : that.media != null) return false; + + return true; + } + + @Override + public int hashCode() + { + int result = media != null ? media.hashCode() : 0; + result = 31 * result + (images != null ? images.hashCode() : 0); + return result; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[MediaContent: "); + sb.append("media=").append(media); + sb.append(", images=").append(images); + sb.append("]"); + return sb.toString(); + } + + public void setMedia(Media media) { + this.media = media; + } + + public void setImages(List images) { + this.images = images; + } + + public Media getMedia() { + return media; + } + + public List getImages() { + return images; + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/BigPerson.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/BigPerson.java new file mode 100644 index 0000000000..9a4f140778 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/BigPerson.java @@ -0,0 +1,153 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.person; + +import java.io.Serializable; + +/** + * @author tony.chenl + */ +public class BigPerson implements Serializable { + private static final long serialVersionUID = 1L; + + String personId; + + String loginName; + + PersonStatus status; + + String email; + + String penName; + + PersonInfo infoProfile; + + public BigPerson() { + + } + + public BigPerson(String id) { + this.personId = id; + } + + public String getPersonId() { + return personId; + } + + public void setPersonId(String personId) { + this.personId = personId; + } + + public PersonInfo getInfoProfile() { + return infoProfile; + } + + public void setInfoProfile(PersonInfo infoProfile) { + this.infoProfile = infoProfile; + } + + public void setLoginName(String loginName) { + this.loginName = loginName; + } + + public void setStatus(PersonStatus status) { + this.status = status; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setPenName(String penName) { + this.penName = penName; + } + + public String getEmail() { + return this.email; + } + + public String getLoginName() { + return this.loginName; + } + + public PersonStatus getStatus() { + return this.status; + } + + public String getPenName() { + return penName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((email == null) ? 0 : email.hashCode()); + result = prime * result + ((infoProfile == null) ? 0 : infoProfile.hashCode()); + result = prime * result + ((loginName == null) ? 0 : loginName.hashCode()); + result = prime * result + ((penName == null) ? 0 : penName.hashCode()); + result = prime * result + ((personId == null) ? 0 : personId.hashCode()); + result = prime * result + ((status == null) ? 0 : status.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BigPerson other = (BigPerson) obj; + if (email == null) { + if (other.email != null) + return false; + } else if (!email.equals(other.email)) + return false; + if (infoProfile == null) { + if (other.infoProfile != null) + return false; + } else if (!infoProfile.equals(other.infoProfile)) + return false; + if (loginName == null) { + if (other.loginName != null) + return false; + } else if (!loginName.equals(other.loginName)) + return false; + if (penName == null) { + if (other.penName != null) + return false; + } else if (!penName.equals(other.penName)) + return false; + if (personId == null) { + if (other.personId != null) + return false; + } else if (!personId.equals(other.personId)) + return false; + if (status != other.status) + return false; + return true; + } + + @Override + public String toString() { + return "BigPerson [personId=" + personId + ", loginName=" + loginName + ", status=" + + status + ", email=" + email + ", penName=" + penName + ", infoProfile=" + + infoProfile + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/FullAddress.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/FullAddress.java new file mode 100644 index 0000000000..45d1e178cb --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/FullAddress.java @@ -0,0 +1,204 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.person; + +import java.io.Serializable; + +/** + * @author xk1430 + */ +public class FullAddress implements Serializable { + + private static final long serialVersionUID = 5163979984269419831L; + + private String countryId; + + private String countryName; + + private String provinceName; + + private String cityId; + + private String cityName; + + private String streetAddress; + + private String zipCode; + + public void setCountryId(String countryId) { + this.countryId = countryId; + } + + public void setCountryName(String countryName) { + this.countryName = countryName; + } + + public void setProvinceName(String provinceName) { + this.provinceName = provinceName; + } + + public void setCityId(String cityId) { + this.cityId = cityId; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public void setStreetAddress(String streetAddress) { + this.streetAddress = streetAddress; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } + + public String getCountryId() { + return countryId; + } + + public String getCountryName() { + return countryName; + } + + public String getProvinceName() { + return provinceName; + } + + public String getCityId() { + return cityId; + } + + public String getCityName() { + return cityName; + } + + public String getStreetAddress() { + return streetAddress; + } + + public String getZipCode() { + return zipCode; + } + + public FullAddress() { + } + + public FullAddress(String countryId, String provinceName, String cityId, String streetAddress, + String zipCode) { + this.countryId = countryId; + this.countryName = countryId; + this.provinceName = provinceName; + this.cityId = cityId; + this.cityName = cityId; + this.streetAddress = streetAddress; + this.zipCode = zipCode; + } + + public FullAddress(String countryId, String countryName, String provinceName, String cityId, + String cityName, String streetAddress, String zipCode) { + this.countryId = countryId; + this.countryName = countryName; + this.provinceName = provinceName; + this.cityId = cityId; + this.cityName = cityName; + this.streetAddress = streetAddress; + this.zipCode = zipCode; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((cityId == null) ? 0 : cityId.hashCode()); + result = prime * result + ((cityName == null) ? 0 : cityName.hashCode()); + result = prime * result + ((countryId == null) ? 0 : countryId.hashCode()); + result = prime * result + ((countryName == null) ? 0 : countryName.hashCode()); + result = prime * result + ((provinceName == null) ? 0 : provinceName.hashCode()); + result = prime * result + ((streetAddress == null) ? 0 : streetAddress.hashCode()); + result = prime * result + ((zipCode == null) ? 0 : zipCode.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FullAddress other = (FullAddress) obj; + if (cityId == null) { + if (other.cityId != null) + return false; + } else if (!cityId.equals(other.cityId)) + return false; + if (cityName == null) { + if (other.cityName != null) + return false; + } else if (!cityName.equals(other.cityName)) + return false; + if (countryId == null) { + if (other.countryId != null) + return false; + } else if (!countryId.equals(other.countryId)) + return false; + if (countryName == null) { + if (other.countryName != null) + return false; + } else if (!countryName.equals(other.countryName)) + return false; + if (provinceName == null) { + if (other.provinceName != null) + return false; + } else if (!provinceName.equals(other.provinceName)) + return false; + if (streetAddress == null) { + if (other.streetAddress != null) + return false; + } else if (!streetAddress.equals(other.streetAddress)) + return false; + if (zipCode == null) { + if (other.zipCode != null) + return false; + } else if (!zipCode.equals(other.zipCode)) + return false; + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (countryName != null && countryName.length() > 0) { + sb.append(countryName); + } + if (provinceName != null && provinceName.length() > 0) { + sb.append(" "); + sb.append(provinceName); + } + if (cityName != null && cityName.length() > 0) { + sb.append(" "); + sb.append(cityName); + } + if (streetAddress != null && streetAddress.length() > 0) { + sb.append(" "); + sb.append(streetAddress); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/PersonInfo.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/PersonInfo.java new file mode 100644 index 0000000000..3534384040 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/PersonInfo.java @@ -0,0 +1,208 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.person; + +import java.io.Serializable; +import java.util.List; + +/** + * @author tony.chenl + */ +public class PersonInfo implements Serializable { + private static final long serialVersionUID = 7443011149612231882L; + + List phones; + + Phone fax; + + FullAddress fullAddress; + + String mobileNo; + + String name; + + boolean male; + + boolean female; + + String department; + + String jobTitle; + + String homepageUrl; + + public List getPhones() { + return phones; + } + + public void setPhones(List phones) { + this.phones = phones; + } + + public boolean isMale() { + return male; + } + + public void setMale(boolean male) { + this.male = male; + } + + public boolean isFemale() { + return female; + } + + public void setFemale(boolean female) { + this.female = female; + } + + public void setFax(Phone fax) { + this.fax = fax; + } + + public void setFullAddress(FullAddress fullAddress) { + this.fullAddress = fullAddress; + } + + public void setMobileNo(String mobileNo) { + this.mobileNo = mobileNo; + } + + public void setName(String name) { + this.name = name; + } + + public void setDepartment(String department) { + this.department = department; + } + + public void setJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + } + + public void setHomepageUrl(String homepageUrl) { + this.homepageUrl = homepageUrl; + } + + public String getDepartment() { + return department; + } + + public Phone getFax() { + return fax; + } + + public FullAddress getFullAddress() { + return fullAddress; + } + + public String getHomepageUrl() { + return homepageUrl; + } + + public String getJobTitle() { + return jobTitle; + } + + public String getMobileNo() { + return mobileNo; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((department == null) ? 0 : department.hashCode()); + result = prime * result + ((fax == null) ? 0 : fax.hashCode()); + result = prime * result + (female ? 1231 : 1237); + result = prime * result + ((fullAddress == null) ? 0 : fullAddress.hashCode()); + result = prime * result + ((homepageUrl == null) ? 0 : homepageUrl.hashCode()); + result = prime * result + ((jobTitle == null) ? 0 : jobTitle.hashCode()); + result = prime * result + (male ? 1231 : 1237); + result = prime * result + ((mobileNo == null) ? 0 : mobileNo.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((phones == null) ? 0 : phones.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PersonInfo other = (PersonInfo) obj; + if (department == null) { + if (other.department != null) + return false; + } else if (!department.equals(other.department)) + return false; + if (fax == null) { + if (other.fax != null) + return false; + } else if (!fax.equals(other.fax)) + return false; + if (female != other.female) + return false; + if (fullAddress == null) { + if (other.fullAddress != null) + return false; + } else if (!fullAddress.equals(other.fullAddress)) + return false; + if (homepageUrl == null) { + if (other.homepageUrl != null) + return false; + } else if (!homepageUrl.equals(other.homepageUrl)) + return false; + if (jobTitle == null) { + if (other.jobTitle != null) + return false; + } else if (!jobTitle.equals(other.jobTitle)) + return false; + if (male != other.male) + return false; + if (mobileNo == null) { + if (other.mobileNo != null) + return false; + } else if (!mobileNo.equals(other.mobileNo)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (phones == null) { + if (other.phones != null) + return false; + } else if (!phones.equals(other.phones)) + return false; + return true; + } + + @Override + public String toString() { + return "PersonInfo [phones=" + phones + ", fax=" + fax + ", fullAddress=" + fullAddress + + ", mobileNo=" + mobileNo + ", name=" + name + ", male=" + male + ", female=" + + female + ", department=" + department + ", jobTitle=" + jobTitle + + ", homepageUrl=" + homepageUrl + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/PersonStatus.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/PersonStatus.java new file mode 100644 index 0000000000..a73d09e7aa --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/PersonStatus.java @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.person; + +/** + * @author tony.chenl + */ +public enum PersonStatus { + ENABLED, + DISABLED +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/Phone.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/Phone.java new file mode 100644 index 0000000000..5063b96392 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/model/person/Phone.java @@ -0,0 +1,143 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.model.person; + +import java.io.Serializable; + +/** + * 电话号码 + * + * @author xk1430 + */ +public class Phone implements Serializable { + + private static final long serialVersionUID = 4399060521859707703L; + + private String country; + + private String area; + + private String number; + + private String extensionNumber; + + public Phone() { + } + + public Phone(String country, String area, String number, String extensionNumber) { + this.country = country; + this.area = area; + this.number = number; + this.extensionNumber = extensionNumber; + } + + public void setCountry(String country) { + this.country = country; + } + + public void setArea(String area) { + this.area = area; + } + + public void setNumber(String number) { + this.number = number; + } + + public void setExtensionNumber(String extensionNumber) { + this.extensionNumber = extensionNumber; + } + + public String getCountry() { + return country; + } + + public String getArea() { + return area; + } + + public String getNumber() { + return number; + } + + public String getExtensionNumber() { + return extensionNumber; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((area == null) ? 0 : area.hashCode()); + result = prime * result + ((country == null) ? 0 : country.hashCode()); + result = prime * result + ((extensionNumber == null) ? 0 : extensionNumber.hashCode()); + result = prime * result + ((number == null) ? 0 : number.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Phone other = (Phone) obj; + if (area == null) { + if (other.area != null) + return false; + } else if (!area.equals(other.area)) + return false; + if (country == null) { + if (other.country != null) + return false; + } else if (!country.equals(other.country)) + return false; + if (extensionNumber == null) { + if (other.extensionNumber != null) + return false; + } else if (!extensionNumber.equals(other.extensionNumber)) + return false; + if (number == null) { + if (other.number != null) + return false; + } else if (!number.equals(other.number)) + return false; + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (country != null && country.length() > 0) { + sb.append(country); + sb.append("-"); + } + if (area != null && area.length() > 0) { + sb.append(area); + sb.append("-"); + } + if (number != null && number.length() > 0) { + sb.append(number); + } + if (extensionNumber != null && extensionNumber.length() > 0) { + sb.append("-"); + sb.append(extensionNumber); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/SerializationCompareTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/SerializationCompareTest.java new file mode 100644 index 0000000000..a0bb1ea6cf --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/SerializationCompareTest.java @@ -0,0 +1,231 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; + +import org.junit.Test; + +import com.alibaba.com.caucho.hessian.io.Hessian2Input; +import com.alibaba.com.caucho.hessian.io.Hessian2Output; +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.serialize.support.dubbo.Builder; +import com.alibaba.dubbo.common.serialize.support.java.CompactedObjectInputStream; +import com.alibaba.dubbo.common.serialize.support.java.CompactedObjectOutputStream; + +/** + * @author qian.lei + * @author ding.lid + */ +public class SerializationCompareTest +{ + @Test + public void test_CompareSerializeLength() throws Exception + { + long[] data = new long[]{ -1l, 2l, 3l, 4l, 5l }; + ByteArrayOutputStream os; + + os = new ByteArrayOutputStream(); + ObjectOutputStream jos = new ObjectOutputStream(os); + jos.writeObject(data); + System.out.println("java:"+Bytes.bytes2hex(os.toByteArray())+":"+os.size()); + + os = new ByteArrayOutputStream(); + CompactedObjectOutputStream oos = new CompactedObjectOutputStream(os); + oos.writeObject(data); + System.out.println("compacted java:"+Bytes.bytes2hex(os.toByteArray())+":"+os.size()); + + os = new ByteArrayOutputStream(); + Hessian2Output h2o = new Hessian2Output(os); + h2o.writeObject(data); + h2o.flushBuffer(); + System.out.println("hessian:"+Bytes.bytes2hex(os.toByteArray())+":"+os.size()); + + os = new ByteArrayOutputStream(); + Builder lb = Builder.register(long[].class); + lb.writeTo(data, os); + System.out.println("DataOutput:"+Bytes.bytes2hex(os.toByteArray())+":"+os.size()); + } + + @Test + public void testBuilderPerm() throws Exception + { + Builder bb = Builder.register(Bean.class); + Bean bean = new Bean(); + int len = 0; + long now = System.currentTimeMillis(); + for(int i=0;i<500;i++) + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + bb.writeTo(bean, os); + os.close(); + if( i == 0 ) + len = os.toByteArray().length; + + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + Bean b = bb.parseFrom(is); + assertEquals(b.getClass(), Bean.class); + } + System.out.println("Builder write and parse 500 times in " + (System.currentTimeMillis()-now)+"ms, size " + len); + } + + @Test + public void testH2oPerm() throws Exception + { + Bean bean = new Bean(); + int len = 0; + long now = System.currentTimeMillis(); + for(int i=0;i<500;i++) + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + Hessian2Output out = new Hessian2Output(os); + out.writeObject(bean); + out.flushBuffer(); + os.close(); + if( i == 0 ) + len = os.toByteArray().length; + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + Hessian2Input in = new Hessian2Input(is); + assertEquals(in.readObject().getClass(), Bean.class); + } + System.out.println("Hessian2 write and parse 500 times in " + (System.currentTimeMillis()-now)+"ms, size " + len); + } + + @Test + public void testJavaOutputPerm() throws Exception + { + Bean bean = new Bean(); + int len = 0; + long now = System.currentTimeMillis(); + for(int i=0;i<500;i++) + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(os); + out.writeObject(bean); + os.close(); + if( i == 0 ) + len = os.toByteArray().length; + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + ObjectInputStream in = new ObjectInputStream(is); + assertEquals(in.readObject().getClass(), Bean.class); + } + System.out.println("java write and parse 500 times in " + (System.currentTimeMillis()-now)+"ms, size " + len); + } + + @Test + public void testCompactedJavaOutputPerm() throws Exception + { + Bean bean = new Bean(); + int len = 0; + long now = System.currentTimeMillis(); + for(int i=0;i<500;i++) + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + CompactedObjectOutputStream out = new CompactedObjectOutputStream(os); + out.writeObject(bean); + os.close(); + if( i == 0 ) + len = os.toByteArray().length; + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + CompactedObjectInputStream in = new CompactedObjectInputStream(is); + assertEquals(in.readObject().getClass(), Bean.class); + } + System.out.println("compacted java write and parse 500 times in " + (System.currentTimeMillis()-now)+"ms, size " + len); + } + + public static enum EnumTest { READ, WRITE, CREATE, UNREGISTER }; + + static class MyList extends ArrayList + { + private static final long serialVersionUID = 1L; + + private int code = 12345; + private String id = "feedback"; + } + + static class MyMap extends HashMap + { + private static final long serialVersionUID = 1L; + + private int code = 12345; + private String id = "feedback"; + } + + public static class Bean implements Serializable + { + private static final long serialVersionUID = 7737610585231102146L; + + public EnumTest ve = EnumTest.CREATE; + + public int vi = 0; + public long vl = 100l; + + boolean b = true; + boolean[] bs = {false, true}; + + String s1 = "1234567890"; + String s2 = "1234567890一二三四五六七八九零"; + + int i = 123123, ni = -12344, is[] = {1,2,3,4,-1,-2,-3,-4}; + short s = 12, ns = -76; + double d = 12.345, nd = -12.345; + long l = 1281447759383l, nl = -13445l; + private ArrayList mylist = new ArrayList(); + { + mylist.add(1); + mylist.add("qianlei"); + mylist.add("qianlei"); + mylist.add("qianlei"); + mylist.add("qianlei"); + } + private HashMap mymap = new HashMap(); + { + mymap.put(1,2); + mymap.put(2,"1234"); + mymap.put("2345",12938.122); + mymap.put("2345",-1); + mymap.put("2345",-1.20); + } + + public ArrayList getMylist() + { + return mylist; + } + + public void setMylist(ArrayList list) + { + mylist = list; + } + + public HashMap getMymap() + { + return mymap; + } + + public void setMymap(HashMap map) + { + mymap = map; + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/dubbo/BuilderTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/dubbo/BuilderTest.java new file mode 100644 index 0000000000..60446019c4 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/dubbo/BuilderTest.java @@ -0,0 +1,525 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.dubbo; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; + +import java.io.Serializable; +import java.sql.Time; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.common.serialize.support.dubbo.Builder; + +public class BuilderTest +{ + @Test + public void testPrimaryTypeBuilder() throws Exception + { + System.out.println((new byte[2]).hashCode()); + Builder builder = Builder.register(String.class); + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + String v = "123"; + builder.writeTo(v, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + v = builder.parseFrom(b); + builder.writeTo(v, os); + b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + } + + @Test + public void testEnumBuilder() throws Exception + { + Builder builder = Builder.register(Type.class); + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + Type v = Type.High; + builder.writeTo(v, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + v = builder.parseFrom(b); + } + + @Test + public void testThrowableBuilder() throws Exception + { + Builder builder = Builder.register(Throwable.class); + Throwable th = new Throwable(); + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + builder.writeTo(th, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + + th = builder.parseFrom(b); + } + + @Test + public void testArrayClassBuilder() throws Exception + { + UnsafeByteArrayOutputStream os; + + byte[] b; + + Builder osb = Builder.register(Object[].class); + os = new UnsafeByteArrayOutputStream(); + osb.writeTo(new Object[]{ new String[0] }, os); + b = os.toByteArray(); + + Builder lsb = Builder.register(long[].class); + os = new UnsafeByteArrayOutputStream(); + lsb.writeTo(new long[]{ 1,121232,-3,4,-5,61321432413l }, os); + lsb.writeTo(new long[]{ 1,121232,-3,4,-5,61321432413l }, os); + lsb.writeTo(new long[]{ 1,2,3,12131314,123132313135l,-6 }, os); + b = os.toByteArray(); + long[] ls = lsb.parseFrom(b); + assertEquals(ls.length, 6); + + Builder bsb = Builder.register(byte[].class); + os = new UnsafeByteArrayOutputStream(); + bsb.writeTo("i am a string.".getBytes(), os); + b = os.toByteArray(); + + Builder iisb = Builder.register(int[][].class); + os = new UnsafeByteArrayOutputStream(); + iisb.writeTo(new int[][]{ {1,2,3,4}, {5,6,7,8}, {9,10}, {122,123,444} }, os); + b = os.toByteArray(); + int[][] iis = iisb.parseFrom(b); + assertEquals(iis.length, 4); + + Builder iiisb = Builder.register(int[][][].class); + os = new UnsafeByteArrayOutputStream(); + iiisb.writeTo(new int[][][]{ + {{1,2,3,4}}, + {{5,6,7,8}}, + {{122,123,444}} + }, os); + b = os.toByteArray(); + int[][][] iii = iiisb.parseFrom(b); + assertEquals(iii.length, 3); + } + + @Test + public void testObjectBuilder() throws Exception + { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + Builder BeanBuilder = Builder.register(Bean.class); + + Bean bean = new Bean(); + bean.name = "ql"; + bean.type = Type.High; + bean.types = new Type[]{ Type.High, Type.High }; + BeanBuilder.writeTo(bean, os); + + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + + bean = BeanBuilder.parseFrom(b); + assertNull(bean.time); + assertEquals(bean.i, 123123); + assertEquals(bean.ni, -12344); + assertEquals(bean.d, 12.345); + assertEquals(bean.nd, -12.345); + assertEquals(bean.l, 1281447759383l); + assertEquals(bean.nl, -13445l); + assertEquals(bean.vl, 100l); + assertEquals(bean.type, Type.High); + assertEquals(bean.types.length, 2); + assertEquals(bean.types[0], Type.High); + assertEquals(bean.types[1], Type.High); + assertEquals(bean.list.size(), 3); + assertEquals(bean.list.get(0), 1); + assertEquals(bean.list.get(1), 2); + assertEquals(bean.list.get(2), 1308147); + } + + @Test + public void testInterfaceBuilder() throws Exception + { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + Builder builder = Builder.register(TestDO.class); + TestDO d = new TestDOImpl(); + builder.writeTo(d, os); + + byte[] b = os.toByteArray(); + + d = builder.parseFrom(b); + assertTrue(TestDO.class.isAssignableFrom(d.getClass())); + assertEquals("name", d.getName()); + assertEquals(28, d.getArg()); + assertEquals(Type.High, d.getType()); + } + + @Test + public void testGenericBuilder() throws Exception + { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + Builder ob = Builder.register(Object.class); + + Object o = new Object(); + ob.writeTo(o, os); + byte[] b = os.toByteArray(); + + os = new UnsafeByteArrayOutputStream(); + Bean bean = new Bean(); + bean.name = "ql"; + bean.type = Type.High; + bean.types = new Type[]{ Type.High, Type.High }; + ob.writeTo(bean, os); + + b = os.toByteArray(); + bean = (Bean)ob.parseFrom(b); + assertEquals(bean.i, 123123); + assertEquals(bean.ni, -12344); + assertEquals(bean.d, 12.345); + assertEquals(bean.nd, -12.345); + assertEquals(bean.l, 1281447759383l); + assertEquals(bean.nl, -13445l); + assertEquals(bean.vl, 100l); + assertEquals(bean.type, Type.High); + assertEquals(bean.types.length, 2); + assertEquals(bean.types[0], Type.High); + assertEquals(bean.types[1], Type.High); + assertEquals(bean.list.size(), 3); + assertEquals(bean.list.get(0), 1); + assertEquals(bean.list.get(1), 2); + assertEquals(bean.list.get(2), 1308147); + } + + @Test + public void testObjectArrayBuilder() throws Exception + { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + Builder builder = Builder.register(Object[].class); + + Object[] obj = new Object[5]; + obj[0] = "1234"; + obj[1] = new Double(109.23); + obj[2] = "3455"; + obj[3] = null; + obj[4] = Boolean.TRUE; + + builder.writeTo(obj, os); + byte[] b = os.toByteArray(); + System.out.println("Object array:"+b.length+":"+Bytes.bytes2hex(b)); + + Assert.assertArrayEquals(obj, builder.parseFrom(b)); + } + + // FIXME MyList的从ArrayList中继承来的属性size会在decode时设置好,再Add时就不对了!! + @Ignore + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testBuilder_MyList() throws Exception + { + Builder b1 = Builder.register(MyList.class); + MyList list = new MyList(); + list.add(new boolean[]{ true,false }); + list.add(new int[]{ 1,2,3,4,5 }); + list.add("String"); + list.add(4); + list.code = 4321; + + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + b1.writeTo(list, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + MyList result = b1.parseFrom(b); + + assertEquals(4, result.size()); + assertEquals(result.code, 4321); + assertEquals(result.id, "feedback"); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testBuilder_MyMap() throws Exception + { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + Builder b2 = Builder.register(MyMap.class); + MyMap map = new MyMap(); + map.put("name", "qianlei"); + map.put("displayName", "钱磊"); + map.code = 4321; + b2.writeTo(map, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + + map = b2.parseFrom(b); + + assertEquals(map.size(), 2); + assertEquals(map.code, 4321); + assertEquals(map.id, "feedback"); + } + + @Test + @SuppressWarnings("unchecked") + public void testSerializableBean() throws Exception + { + System.out.println("testSerializableBean"); + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + + SerializableBean sb = new SerializableBean(); + Builder sbb = Builder.register(SerializableBean.class); + sbb.writeTo(sb, os); + + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + assertEquals(sbb.parseFrom(os.toByteArray()), sb); + } + + @Test + @SuppressWarnings("unchecked") + public void testOthers() throws Exception + { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + + StringBuffer buf = new StringBuffer(); + for(int i=0;i<1024*32+32;i++) + buf.append('A'); + Builder sb = Builder.register(String.class); + sb.writeTo(buf.toString(), os); + assertEquals(sb.parseFrom(os.toByteArray()), buf.toString()); + + os = new UnsafeByteArrayOutputStream(); + Builder builder = Builder.register(HashMap.class); + Map services = new HashMap(); + HashMap map = new HashMap(); + services.put("test.service", "http://127.0.0.1:9010/test.service"); + map.put("name", "qianlei"); + map.put("password", "123455"); + map.put("services", services); + + builder.writeTo(map, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + map = builder.parseFrom(b); + assertTrue(map.size() > 0); + assertEquals("http://127.0.0.1:9010/test.service", ((Map) map.get("services")).get("test.service")); + + services = new ConcurrentHashMap(); + services.put("test.service", "http://127.0.0.1:9010/test.service"); + map.put("services", services); + + os = new UnsafeByteArrayOutputStream(); + builder.writeTo(map, os); + b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + map = builder.parseFrom(b); + assertTrue(map.size() > 0); + assertEquals("http://127.0.0.1:9010/test.service", ((Map) map.get("services")).get("test.service")); + + Node node1 = new Node(); + Node node0 = new Node(); + node0.value = "0"; + node0.next = node1; + node1.value = "1"; + node1.prev = node0; + // write. + Builder nodebuilder = Builder.register(Node.class); + os = new UnsafeByteArrayOutputStream(); + nodebuilder.writeTo(node0, os); + b = os.toByteArray(); + System.out.println("Node:"+b.length+":"+Bytes.bytes2hex(b)); + // parse + node0 = nodebuilder.parseFrom(b); + assertEquals(node0, node0.prev); + assertEquals(node0, node0.next.prev); + assertEquals(node0.value, "0"); + } + + @Test + public void testWithFC() throws Exception + { + Builder builder = Builder.register(SimpleDO.class); + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + + SimpleDO sd = new SimpleDO(); + sd.a = 1; + sd.b = 2; + sd.c = 3; + sd.str1 = "12345"; + sd.str2 = "54321"; + builder.writeTo(sd, os); + byte[] b = os.toByteArray(); + System.out.println(b.length+":"+Bytes.bytes2hex(b)); + + sd = builder.parseFrom(b); + assertEquals(sd.a, 1); + assertEquals(sd.b, 2); + assertEquals(sd.c, 3); + assertEquals(sd.str1, "124"); + System.out.println(sd.str2); + } + + public enum Type + { + Lower, Normal, High; + } + + static interface TestDO + { + String getName(); + void setName(String name); + Type getType(); + void setType(Type t); + int getArg(); + void setArg(int arg); + } + + static class TestDOImpl implements TestDO, Serializable + { + private static final long serialVersionUID = 1L; + public String getName() + { + return "name"; + } + public void setName(String name){} + public Type getType() + { + return Type.High; + } + public void setType(Type t){} + public int getArg() + { + return 28; + } + public void setArg(int arg){} + } + + static class Bean implements Serializable + { + private static final long serialVersionUID = 1L; + public int vi = 0; + public long vl = 100l; + + boolean b = true; + boolean[] bs = {false, true}; + + String s1 = "1234567890"; + String s2 = "1234567890一二三四五六七八九零"; + + private int i = 123123, ni = -12344, is[] = {1,2,3,4,-1,-2,-3,-4}; + private short s = 12, ns = -76; + private double d = 12.345, nd = -12.345; + private long l = 1281447759383l, nl = -13445l; + + private Boolean B = Boolean.FALSE; + private Integer I = -1234; + private Double D = new Double(1.23); + private String name = "qianlei"; + private Type type = Type.Lower, type1 = Type.Normal; + private Type[] types = { Type.Lower, Type.Lower }; + + private Time time = null; + + public Type getType() + { + return type; + } + + public void setType(Type type) + { + this.type = type; + } + + private ArrayList list = new ArrayList(); + { + list.add(1); + list.add(2); + list.add(1308147); + } + } + + static class MyList extends ArrayList + { + private int code = 12345; + private String id = "feedback"; + } + + static class MyMap extends HashMap + { + private int code = 12345; + private String id = "feedback"; + } + + static class Node implements Serializable + { + private static final long serialVersionUID = 1L; + Node prev = this; + Node next = this; + String value = "value"; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Node other = (Node) obj; + if (value == null) { + if (other.value != null) return false; + } else if (!value.equals(other.value)) return false; + return true; + } + } + + static class SerializableBean implements Serializable + { + private static final long serialVersionUID = -8949681707161463700L; + + public int a = 0; + public long b = 100l; + boolean c = true; + String s1 = "1234567890"; + String s2 = "1234567890一二三四五六七八九零"; + + public int hashCode() + { + return s1.hashCode() ^ s2.hashCode(); + } + + public boolean equals(Object obj) + { + if( obj == null ) return false; + if( obj == this ) return true; + if( obj instanceof SerializableBean ) + { + SerializableBean sb = (SerializableBean)obj; + return this.a == sb.a && this.b == sb.b && this.c == sb.c && this.s1.equals(sb.s1) && this.s2.equals(sb.s2); + } + + return false; + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/dubbo/DataInputOutputTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/dubbo/DataInputOutputTest.java new file mode 100644 index 0000000000..cfaf8a0185 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/dubbo/DataInputOutputTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.dubbo; + +import java.io.IOException; + +import junit.framework.TestCase; + +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.common.serialize.DataInput; +import com.alibaba.dubbo.common.serialize.DataOutput; +import com.alibaba.dubbo.common.serialize.support.dubbo.GenericDataInput; +import com.alibaba.dubbo.common.serialize.support.dubbo.GenericDataOutput; + +public class DataInputOutputTest extends TestCase +{ + private static final String SMALL_STRING = DataInputOutputTest.class.getName(), BIG_STREAM = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + + private static final byte[] SMALL_BYTES = SMALL_STRING.getBytes(), BIG_BYTES = BIG_STREAM.getBytes(); + + public void testMain() throws Exception + { + // write. + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(); + DataOutput cos = new GenericDataOutput(os); + writeTest(cos); + + // read. + byte[] b = os.toByteArray(); + DataInput cis = new GenericDataInput(new UnsafeByteArrayInputStream(b)); + readTest(cis); + } + + private void writeTest(DataOutput out) throws IOException + { + out.writeShort((short)'a'); + out.writeShort((short)-1); + out.writeShort((short)1234); + out.writeInt(0x22); + out.writeInt(-0x22); + out.writeInt(0x2222); + out.writeInt(-0x2222); + out.writeInt(0x222222); + out.writeInt(-0x222222); + out.writeInt(0x22222222); + out.writeInt(-0x22222222); + out.writeLong(0x22); + out.writeLong(-0x22); + out.writeLong(0x2222); + out.writeLong(-0x2222); + out.writeLong(0x222222); + out.writeLong(-0x222222); + out.writeLong(0x22222222); + out.writeLong(-0x22222222); + out.writeLong(0x2222222222l); + out.writeLong(-0x2222222222l); + out.writeLong(0x222222222222l); + out.writeLong(-0x222222222222l); + out.writeLong(0x22222222222222l); + out.writeLong(-0x22222222222222l); + out.writeLong(0x2222222222222222l); + out.writeLong(-0x2222222222222222l); + out.writeDouble(1212.454); + out.writeBytes(SMALL_BYTES); + out.writeUTF(SMALL_STRING); + out.writeBytes(BIG_BYTES); + out.flushBuffer(); + } + + private void readTest(DataInput in) throws IOException + { + assertEquals(in.readShort(), 'a'); + assertEquals(in.readShort(), -1); + assertEquals(in.readShort(), 1234); + assertEquals(in.readInt(), 0x22); + assertEquals(in.readInt(), -0x22); + assertEquals(in.readInt(), 0x2222); + assertEquals(in.readInt(), -0x2222); + assertEquals(in.readInt(), 0x222222); + assertEquals(in.readInt(), -0x222222); + assertEquals(in.readInt(), 0x22222222); + assertEquals(in.readInt(), -0x22222222); + assertEquals(in.readLong(), 0x22); + assertEquals(in.readLong(), -0x22); + assertEquals(in.readLong(), 0x2222); + assertEquals(in.readLong(), -0x2222); + assertEquals(in.readLong(), 0x222222); + assertEquals(in.readLong(), -0x222222); + assertEquals(in.readLong(), 0x22222222); + assertEquals(in.readLong(), -0x22222222); + assertEquals(in.readLong(), 0x2222222222l); + assertEquals(in.readLong(), -0x2222222222l); + assertEquals(in.readLong(), 0x222222222222l); + assertEquals(in.readLong(), -0x222222222222l); + assertEquals(in.readLong(), 0x22222222222222l); + assertEquals(in.readLong(), -0x22222222222222l); + assertEquals(in.readLong(), 0x2222222222222222l); + assertEquals(in.readLong(), -0x2222222222222222l); + assertEquals(in.readDouble(), 1212.454); + assertSameArray(in.readBytes(), SMALL_BYTES); + assertEquals(in.readUTF(), SMALL_STRING); + assertSameArray(in.readBytes(), BIG_BYTES); + } + + private static void assertSameArray(byte[] b1, byte[] b2) + { + assertEquals(b1.length, b2.length); + for(int i=0;i args = new ArrayList(); + args.add(new Person()); + try { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(args); + fail(); + } + catch (NotSerializableException expected) {} + catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Serialized class com.alibaba.dubbo.common.model.Person must implement java.io.Serializable")); + } + } + + @Test + public void test_PersonSet() throws Exception { + Set args = new HashSet(); + args.add(new Person()); + try { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(args); + fail(); + } + catch (NotSerializableException expected) {} + catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Serialized class com.alibaba.dubbo.common.model.Person must implement java.io.Serializable")); + } + } + + @Test + public void test_IntPersonMap() throws Exception { + Map args = new HashMap(); + args.put(1, new Person()); + try { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(args); + fail(); + } + catch (NotSerializableException expected) {} + catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Serialized class com.alibaba.dubbo.common.model.Person must implement java.io.Serializable")); + } + } + + @Test + public void test_StringPersonMap() throws Exception { + Map args = new HashMap(); + args.put("1", new Person()); + try { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(args); + fail(); + } + catch (NotSerializableException expected) {} + catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Serialized class com.alibaba.dubbo.common.model.Person must implement java.io.Serializable")); + } + } + + @Test + public void test_StringPersonListMap() throws Exception { + Map> args = new HashMap>(); + + List sublist = new ArrayList(); + sublist.add(new Person()); + args.put("1", sublist); + try { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(args); + fail(); + } + catch (NotSerializableException expected) {} + catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Serialized class com.alibaba.dubbo.common.model.Person must implement java.io.Serializable")); + } + } + + @Test + public void test_PersonListList() throws Exception { + List> args = new ArrayList>(); + List sublist = new ArrayList(); + sublist.add(new Person()); + args.add(sublist); + try { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(args); + fail(); + } + catch (NotSerializableException expected) {} + catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString("Serialized class com.alibaba.dubbo.common.model.Person must implement java.io.Serializable")); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/AbstractSerializationPersionOkTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/AbstractSerializationPersionOkTest.java new file mode 100644 index 0000000000..aa50ceb932 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/AbstractSerializationPersionOkTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; + +import com.alibaba.dubbo.common.model.Person; + +/** + * @author ding.lid + */ +public abstract class AbstractSerializationPersionOkTest extends AbstractSerializationTest { + @Test + public void test_Person() throws Exception { + assertObject(new Person()); + } + + @Test + public void test_Person_withType() throws Exception { + assertObjectWithType(new Person(), Person.class); + } + + @Test + public void test_PersonList() throws Exception { + List args = new ArrayList(); + args.add(new Person()); + + assertObject(args); + } + + @Test + public void test_PersonSet() throws Exception { + Set args = new HashSet(); + args.add(new Person()); + + assertObject(args); + } + + @Test + public void test_IntPersonMap() throws Exception { + Map args = new HashMap(); + args.put(1, new Person()); + + assertObject(args); + } + + @Test + public void test_StringPersonMap() throws Exception { + Map args = new HashMap(); + args.put("1", new Person()); + + assertObject(args); + } + + @Test + public void test_StringPersonListMap() throws Exception { + Map> args = new HashMap>(); + + List sublist = new ArrayList(); + sublist.add(new Person()); + args.put("1", sublist); + + assertObject(args); + } + + @Test + public void test_PersonListList() throws Exception { + List> args = new ArrayList>(); + List sublist = new ArrayList(); + sublist.add(new Person()); + args.add(sublist); + + assertObject(args); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/AbstractSerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/AbstractSerializationTest.java new file mode 100644 index 0000000000..4d04614db0 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/AbstractSerializationTest.java @@ -0,0 +1,1188 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.model.AnimalEnum; +import com.alibaba.dubbo.common.model.BizException; +import com.alibaba.dubbo.common.model.BizExceptionNoDefaultConstructor; +import com.alibaba.dubbo.common.model.SerializablePerson; +import com.alibaba.dubbo.common.model.media.Image; +import com.alibaba.dubbo.common.model.media.Image.Size; +import com.alibaba.dubbo.common.model.media.Media; +import com.alibaba.dubbo.common.model.media.Media.Player; +import com.alibaba.dubbo.common.model.media.MediaContent; +import com.alibaba.dubbo.common.model.person.BigPerson; +import com.alibaba.dubbo.common.model.person.FullAddress; +import com.alibaba.dubbo.common.model.person.PersonInfo; +import com.alibaba.dubbo.common.model.person.PersonStatus; +import com.alibaba.dubbo.common.model.person.Phone; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; + +/** + * @author ding.lid + */ +public abstract class AbstractSerializationTest { + Serialization serialization; + + URL url = new URL("protocl", "1.1.1.1", 1234); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + static Random random = new Random(); + + // ================ Primitive Type ================ + + @Test + public void test_Bool() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeBool(false); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertFalse(deserialize.readBool()); + + try { + deserialize.readBool(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Bool_Multi() throws Exception { + boolean[] array = new boolean[100]; + for (int i = 0; i < array.length; i++) { + array[i] = random.nextBoolean(); + } + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + for (boolean b : array) { + objectOutput.writeBool(b); + } + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + for (boolean b : array) { + assertEquals(b, deserialize.readBool()); + } + + try { + deserialize.readBool(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Byte() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeByte((byte) 123); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals((byte) 123, deserialize.readByte()); + + try { + deserialize.readByte(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Byte_Multi() throws Exception { + byte[] array = new byte[100]; + random.nextBytes(array); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + for (byte b : array) { + objectOutput.writeByte(b); + } + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + for (byte b : array) { + assertEquals(b, deserialize.readByte()); + } + + try { + deserialize.readByte(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Short() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeShort((short) 123); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals((short) 123, deserialize.readShort()); + + try { + deserialize.readShort(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Integer() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeInt(1); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + int i = deserialize.readInt(); + assertEquals(1, i); + + try { + deserialize.readInt(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Long() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeLong(123L); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals(123L, deserialize.readLong()); + + try { + deserialize.readLong(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Float() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeFloat(1.28F); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertTrue(1.28F == deserialize.readFloat()); + + try { + deserialize.readFloat(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Double() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeDouble(1.28); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertTrue(1.28 == deserialize.readDouble()); + + try { + deserialize.readDouble(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_UtfString() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeUTF("123中华人民共和国"); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals("123中华人民共和国", deserialize.readUTF()); + + try { + deserialize.readUTF(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_Bytes() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeBytes("123中华人民共和国".getBytes()); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals("123中华人民共和国".getBytes(), deserialize.readBytes()); + + try { + deserialize.readBytes(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_BytesRange() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeBytes("123中华人民共和国-新疆维吾尔自治区".getBytes(), 1, 9); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + byte[] expectedArray = new byte[9]; + System.arraycopy("123中华人民共和国-新疆维吾尔自治区".getBytes(), 1, expectedArray, 0, expectedArray.length); + assertArrayEquals(expectedArray, deserialize.readBytes()); + + try { + deserialize.readBytes(); + fail(); + } catch (IOException expected) {} + } + + // ================== Util methods ================== + + void assertObjectArray(T[] data, Class clazz) throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, clazz.cast(deserialize.readObject())); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + void assertObjectArrayWithType(T[] data, Class clazz) throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, clazz.cast(deserialize.readObject(clazz))); + + try { + deserialize.readObject(clazz); + fail(); + } catch (IOException expected) { + } + } + + @SuppressWarnings("unchecked") + void assertObject(T data) throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals(data, (T) deserialize.readObject()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + void assertObjectWithType(T data, Class clazz) throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals(data, (T) deserialize.readObject(clazz)); + + try { + deserialize.readObject(clazz); + fail(); + } catch (IOException expected) { + } + } + + // ================ Array Type ================ + + @Test + public void test_boolArray() throws Exception { + boolean[] data = new boolean[] { true, false, true}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertTrue(Arrays.equals(data, (boolean[]) deserialize.readObject())); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_boolArray_withType() throws Exception { + boolean[] data = new boolean[] { true, false, true}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertTrue(Arrays.equals(data, (boolean[]) deserialize.readObject(boolean[].class))); + + try { + deserialize.readObject(boolean[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_charArray() throws Exception { + char[] data = new char[] { 'a', '中', '无' }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (char[]) deserialize.readObject()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_charArray_withType() throws Exception { + char[] data = new char[] { 'a', '中', '无' }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (char[]) deserialize.readObject(char[].class)); + + try { + deserialize.readObject(char[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_shortArray() throws Exception { + short[] data = new short[] { 37, 39, 12 }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (short[]) deserialize.readObject()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_shortArray_withType() throws Exception { + short[] data = new short[] { 37, 39, 12 }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (short[]) deserialize.readObject(short[].class)); + + try { + deserialize.readObject(short[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_intArray() throws Exception { + int[] data = new int[] { 234, 0, -1}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (int[]) deserialize.readObject()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_intArray_withType() throws Exception { + int[] data = new int[] { 234, 0, -1}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (int[]) deserialize.readObject(int[].class)); + + try { + deserialize.readObject(int[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_longArray() throws Exception { + long[] data = new long[] { 234, 0, -1}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (long[]) deserialize.readObject()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_longArray_withType() throws Exception { + long[] data = new long[] { 234, 0, -1}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (long[]) deserialize.readObject(long[].class)); + + try { + deserialize.readObject(long[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_floatArray() throws Exception { + float[] data = new float[] { 37F, -3.14F, 123456.7F }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (float[]) deserialize.readObject(), 0.0001F); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_floatArray_withType() throws Exception { + float[] data = new float[] { 37F, -3.14F, 123456.7F }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (float[]) deserialize.readObject(float[].class), 0.0001F); + + try { + deserialize.readObject(float[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_doubleArray() throws Exception { + double[] data = new double[] { 37D, -3.14D, 123456.7D }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (double[]) deserialize.readObject(), 0.0001); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_doubleArray_withType() throws Exception { + double[] data = new double[] { 37D, -3.14D, 123456.7D }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (double[]) deserialize.readObject(double[].class), 0.0001); + + try { + deserialize.readObject(double[].class); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_StringArray() throws Exception { + assertObjectArray(new String[] { "1", "b" }, String[].class); + } + + @Test + public void test_StringArray_withType() throws Exception { + assertObjectArrayWithType(new String[] { "1", "b" }, String[].class); + } + + @Test + public void test_IntegerArray() throws Exception { + assertObjectArray(new Integer[] { 234, 0, -1}, Integer[].class); + } + + @Test + public void test_IntegerArray_withType() throws Exception { + assertObjectArrayWithType(new Integer[] { 234, 0, -1}, Integer[].class); + } + + @Test + public void test_EnumArray() throws Exception { + assertObjectArray(new AnimalEnum[] { AnimalEnum.bull, AnimalEnum.cat, AnimalEnum.dog, AnimalEnum.horse}, AnimalEnum[].class); + } + + @Test + public void test_EnumArray_withType() throws Exception { + assertObjectArrayWithType(new AnimalEnum[] { AnimalEnum.bull, AnimalEnum.cat, AnimalEnum.dog, AnimalEnum.horse}, AnimalEnum[].class); + } + + // ================ Simple Type ================ + + @Test + public void test_SPerson() throws Exception { + assertObject(new SerializablePerson()); + } + + @Test + public void test_SPerson_withType() throws Exception { + assertObjectWithType(new SerializablePerson(), SerializablePerson.class); + } + + @Test + public void test_BizException() throws Exception { + BizException e = new BizException("Hello"); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(e); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + Object read = deserialize.readObject(); + assertEquals("Hello", ((BizException) read).getMessage()); + } + + @Test + public void test_BizException_WithType() throws Exception { + BizException e = new BizException("Hello"); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(e); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + Object read = deserialize.readObject(BizException.class); + assertEquals("Hello", ((BizException) read).getMessage()); + } + + @Test + public void test_BizExceptionNoDefaultConstructor() throws Exception { + BizExceptionNoDefaultConstructor e = new BizExceptionNoDefaultConstructor("Hello"); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(e); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + Object read = deserialize.readObject(); + assertEquals("Hello", ((BizExceptionNoDefaultConstructor) read).getMessage()); + } + + @Test + public void test_BizExceptionNoDefaultConstructor_WithType() throws Exception { + BizExceptionNoDefaultConstructor e = new BizExceptionNoDefaultConstructor("Hello"); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(e); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + Object read = deserialize.readObject(BizExceptionNoDefaultConstructor.class); + assertEquals("Hello", ((BizExceptionNoDefaultConstructor) read).getMessage()); + } + + @Test + public void test_enum() throws Exception { + assertObject(AnimalEnum.dog); + } + + @Test + public void test_enum_withType() throws Exception { + assertObjectWithType(AnimalEnum.dog, AnimalEnum.class); + } + + @Test + public void test_Date() throws Exception { + assertObject(new Date()); + } + + @Test + public void test_Date_withType() throws Exception { + assertObjectWithType(new Date(), Date.class); + } + + @Test + public void test_Time() throws Exception { + assertObject(new Time(System.currentTimeMillis())); + } + + @Test + public void test_Time_withType() throws Exception { + assertObjectWithType(new Time(System.currentTimeMillis()), Time.class); + } + + @Test + public void test_ByteWrap() throws Exception { + assertObject(new Byte((byte) 12)); + } + + @Test + public void test_ByteWrap_withType() throws Exception { + assertObjectWithType(new Byte((byte) 12), Byte.class); + } + + @Test + public void test_LongWrap() throws Exception { + assertObject(new Long(12)); + } + + @Test + public void test_LongWrap_withType() throws Exception { + assertObjectWithType(new Long(12), Long.class); + } + + @Test + public void test_BigInteger() throws Exception { + assertObject(new BigInteger("23423434234234234")); + } + + @Test + public void test_BigInteger_withType() throws Exception { + assertObjectWithType(new BigInteger("23423434234234234"), BigInteger.class); + } + + @Test + public void test_BigDecimal() throws Exception { + assertObject(new BigDecimal("23423434234234234.341274832341234235")); + } + + @Test + public void test_BigDecimal_withType() throws Exception { + assertObjectWithType(new BigDecimal("23423434234234234.341274832341234235"), BigDecimal.class); + } + + @Test + public void test_StringList_asListReturn() throws Exception { + List args = Arrays.asList(new String[] { "1", "b" }); + + assertObject(args); + } + + @Test + public void test_StringArrayList() throws Exception { + List args = new ArrayList(Arrays.asList(new String[] { "1", "b" })); + + assertObject(args); + } + + @Test + public void test_StringSet() throws Exception { + Set args = new HashSet(); + args.add("1"); + + assertObject(args); + } + + @Test + public void test_LinkedHashMap() throws Exception { + LinkedHashMap data = new LinkedHashMap(); + data.put("1", "a"); + data.put("2", "b"); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + Object read = deserialize.readObject(); + assertTrue(read instanceof LinkedHashMap); + @SuppressWarnings("unchecked") + String key1 = ((LinkedHashMap)read).entrySet().iterator().next().getKey(); + assertEquals("1", key1); + + assertEquals(data, read); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_SPersonList() throws Exception { + List args = new ArrayList(); + args.add(new SerializablePerson()); + + assertObject(args); + } + + @Test + public void test_SPersonSet() throws Exception { + Set args = new HashSet(); + args.add(new SerializablePerson()); + + assertObject(args); + } + + @Test + public void test_IntSPersonMap() throws Exception { + Map args = new HashMap(); + args.put(1, new SerializablePerson()); + + assertObject(args); + } + + @Test + public void test_StringSPersonMap() throws Exception { + Map args = new HashMap(); + args.put("1", new SerializablePerson()); + + assertObject(args); + } + + // ================ Complex Collection Type ================ + + @Test + public void test_StringSPersonListMap() throws Exception { + Map> args = new HashMap>(); + + List sublist = new ArrayList(); + sublist.add(new SerializablePerson()); + args.put("1", sublist); + + assertObject(args); + } + + @Test + public void test_SPersonListList() throws Exception { + List> args = new ArrayList>(); + List sublist = new ArrayList(); + sublist.add(new SerializablePerson()); + args.add(sublist); + + assertObject(args); + } + + // ================ complex POJO ============= + + BigPerson bigPerson; + { + bigPerson = new BigPerson(); + bigPerson.setPersonId("superman111"); + bigPerson.setLoginName("superman"); + bigPerson.setStatus(PersonStatus.ENABLED); + bigPerson.setEmail("sm@1.com"); + bigPerson.setPenName("pname"); + + ArrayList phones = new ArrayList(); + Phone phone1 = new Phone("86", "0571", "87654321", "001"); + Phone phone2 = new Phone("86", "0571", "87654322", "002"); + phones.add(phone1); + phones.add(phone2); + + PersonInfo pi = new PersonInfo(); + pi.setPhones(phones); + Phone fax = new Phone("86", "0571", "87654321", null); + pi.setFax(fax); + FullAddress addr = new FullAddress("CN", "zj", "3480", "wensanlu", "315000"); + pi.setFullAddress(addr); + pi.setMobileNo("13584652131"); + pi.setMale(true); + pi.setDepartment("b2b"); + pi.setHomepageUrl("www.capcom.com"); + pi.setJobTitle("qa"); + pi.setName("superman"); + + bigPerson.setInfoProfile(pi); + } + + @Test + public void test_BigPerson() throws Exception { + assertObject(bigPerson); + } + + @Test + public void test_BigPerson_WithType() throws Exception { + assertObjectWithType(bigPerson, BigPerson.class); + } + + MediaContent mediaContent; + { + Media media = new Media(); + media.setUri("uri://中华人民共和国"); + media.setTitle("title"); + media.setWidth(1239); + media.setHeight(1938); + media.setFormat("format-xxxx"); + media.setDuration(93419235); + media.setSize(3477897); + media.setBitrate(94523); + List persons = new ArrayList(); + persons.add("jerry"); + persons.add("tom"); + persons.add("lucy"); + media.setPersons(persons); + media.setCopyright("1999-2011"); + media.setPlayer(Player.FLASH); + + List images = new ArrayList(); + for(int i = 0; i < 10; ++i) { + Image image = new Image(); + image.setUri("url" + i); + if(i % 2 == 0) image.setTitle("title" + i); + image.setWidth(34 + i); + image.setHeight(2323 + i); + image.setSize((i % 2 == 0) ? Size.SMALL : Size.LARGE); + + images.add(image); + } + + mediaContent = new MediaContent(media, images); + } + + @Test + public void test_MediaContent() throws Exception { + assertObject(mediaContent); + } + + @Test + public void test_MediaContent_WithType() throws Exception { + assertObjectWithType(mediaContent, MediaContent.class); + } + + @Test + public void test_MultiObject() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeBool(false); + objectOutput.writeObject(bigPerson); + objectOutput.writeByte((byte) 23); + objectOutput.writeObject(mediaContent); + objectOutput.writeInt(-23); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals(false, deserialize.readBool()); + assertEquals(bigPerson, deserialize.readObject()); + assertEquals((byte) 23, deserialize.readByte()); + assertEquals(mediaContent, deserialize.readObject()); + assertEquals(-23, deserialize.readInt()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + @Test + public void test_MultiObject_WithType() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeBool(false); + objectOutput.writeObject(bigPerson); + objectOutput.writeByte((byte) 23); + objectOutput.writeObject(mediaContent); + objectOutput.writeInt(-23); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertEquals(false, deserialize.readBool()); + assertEquals(bigPerson, deserialize.readObject(BigPerson.class)); + assertEquals((byte) 23, deserialize.readByte()); + assertEquals(mediaContent, deserialize.readObject(MediaContent.class)); + assertEquals(-23, deserialize.readInt()); + + try { + deserialize.readObject(); + fail(); + } catch (IOException expected) { + } + } + + + // abnormal case + + @Test + public void test_MediaContent_badStream() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(mediaContent); + objectOutput.flushBuffer(); + + byte[] byteArray = byteArrayOutputStream.toByteArray(); + for (int i = 0; i < byteArray.length; i++) { + if(i%3 == 0) { + byteArray[i] = (byte)~byteArray[i]; + } + } + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); + + try { + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + @SuppressWarnings("unused") // local variable, convenient for debug + Object read = deserialize.readObject(); + fail(); + } catch (IOException expected) { + System.out.println(expected); + } + } + + @Test + public void test_MediaContent_WithType_badStream() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(mediaContent); + objectOutput.flushBuffer(); + + byte[] byteArray = byteArrayOutputStream.toByteArray(); + for (int i = 0; i < byteArray.length; i++) { + if(i%3 == 0) { + byteArray[i] = (byte)~byteArray[i]; + } + } + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); + + try { + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + @SuppressWarnings("unused") // local variable, convenient for debug + Object read = deserialize.readObject(MediaContent.class); + fail(); + } catch (IOException expected) { + System.out.println(expected); + } + } + + + @Test(timeout=3000) + public void test_LoopReference() throws Exception { + Map map= new HashMap(); + map.put("k1", "v1"); + map.put("self", map); + + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(map); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + @SuppressWarnings("unchecked") + Map output = (Map) deserialize.readObject(); + + assertEquals("v1", output.get("k1")); + assertSame(output, output.get("self")); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/CompactedJavaSerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/CompactedJavaSerializationTest.java new file mode 100644 index 0000000000..a36f7eeb7d --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/CompactedJavaSerializationTest.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import com.alibaba.dubbo.common.serialize.support.java.CompactedJavaSerialization; + +/** + * @author ding.lid + * + */ +public class CompactedJavaSerializationTest extends AbstractSerializationPersionFailTest { + { + serialization = new CompactedJavaSerialization(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/DubboSerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/DubboSerializationTest.java new file mode 100644 index 0000000000..57ab66b934 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/DubboSerializationTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.serialize.support.dubbo.DubboSerialization; + +/** + * @author ding.lid + * + */ +public class DubboSerializationTest extends AbstractSerializationPersionFailTest { + { + serialization = new DubboSerialization(); + } + + // FIXME + @Ignore("DubboSerialization error: java.lang.IllegalAccessError: tried to access class java.util.Arrays$ArrayList from class com.alibaba.dubbo.common.serialize.support.dubbo.Builder$bc6") + @Test + public void test_StringList_asListReturn() throws Exception {} + + // FIXME + @Ignore("NPE") + @Test + public void test_BigInteger() throws Exception {} + + // FIXME + @Ignore("NPE") + @Test + public void test_BigInteger_withType() throws Exception {} + + // FIXME + @Ignore("StackOverflowError") + @Test(timeout=3000) + public void test_LoopReference() throws Exception {} +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/FastJsonSerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/FastJsonSerializationTest.java new file mode 100644 index 0000000000..e0178363f9 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/FastJsonSerializationTest.java @@ -0,0 +1,261 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; + +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.model.media.MediaContent; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.support.json.FastJsonSerialization; +import com.alibaba.fastjson.JSONException; + +/** + * FIXME FastJson Serialization的失败,被暂时被忽略 + * + * @author ding.lid + */ +public class FastJsonSerializationTest extends AbstractSerializationPersionOkTest { + { + serialization = new FastJsonSerialization(); + } + + @Ignore // FIXME + @Test + public void test_BytesRange() throws Exception {} + + @Ignore("bool[] type missing to JSONArray") + @Test + public void test_boolArray() throws Exception {} + + @Ignore("FastJson bug: com.alibaba.fastjson.JSONException: create asm serilizer error, class char") + @Test + public void test_charArray() throws Exception {} + + @Ignore("FastJson bug: com.alibaba.fastjson.JSONException: create asm serilizer error, class char") + @Test + public void test_charArray_withType() throws Exception {} + + @Ignore("short[] type missing to JSONArray") + @Test + public void test_shortArray() throws Exception {} + + @Ignore("int[] type missing to JSONArray") + @Test + public void test_intArray() throws Exception {} + + @Ignore("long[] type missing to JSONArray") + @Test + public void test_longArray() throws Exception {} + + @Ignore("float[] type missing to JSONArray") + @Test + public void test_floatArray() throws Exception {} + + @Ignore("double[] type missing to JSONArray") + @Test + public void test_doubleArray() throws Exception {} + + @Ignore("String[] type missing to JSONArray") + @Test + public void test_StringArray() throws Exception {} + + @Ignore("Integer[] type missing to JSONArray") + @Test + public void test_IntegerArray() throws Exception {} + + @Ignore("Integer[] type missing to JSONArray") + @Test + public void test_EnumArray() throws Exception {} + + @Ignore("type mising to Long") + @Test + public void test_Date() throws Exception {} + + @Ignore("type mising to Long") + @Test + public void test_Time() throws Exception {} + + @Ignore("com.alibaba.fastjson.JSONException: create asm deserializer error, java.sql.Time") + @Test + public void test_Time_withType() throws Exception {} + + @Ignore("type mising to Integer") + @Test + public void test_ByteWrap() throws Exception {} + + @Ignore("type mising to Integer") + @Test + public void test_LongWrap() throws Exception {} + + @Ignore("type mising to Long") + @Test + public void test_BigInteger() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_SPerson() throws Exception {} + + @Ignore("BizException type missing to Map") + @Test + public void test_BizException() throws Exception {} + + @Ignore("BizExceptionNoDefaultConstructor type missing to Map") + @Test + public void test_BizExceptionNoDefaultConstructor() throws Exception {} + + // FIXME 没有缺省构造函数失败 + @Ignore("NoDefaultConstructor") + @Test + public void test_BizExceptionNoDefaultConstructor_WithType() throws Exception {} + + @Ignore("Enum type missing to String") + @Test + public void test_enum() throws Exception {} + + @Ignore("String set missing to JSONArray") + @Test + public void test_StringSet() throws Exception {} + + @Ignore("LinkedHashMap type missing to Map") + @Test + public void test_LinkedHashMap() throws Exception {} + + + @Ignore("person type missing") + @Test + public void test_SPersonList() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_SPersonSet() throws Exception {} + + @Ignore("FastJson bug: com.alibaba.fastjson.JSONException: illegal identifier : 1") + @Test + public void test_IntSPersonMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_StringSPersonMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_StringSPersonListMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_SPersonListList() throws Exception {} + + @Ignore("BigPerson type missing") + @Test + public void test_BigPerson() throws Exception {} + + @Ignore("MediaContent type missing") + @Test + public void test_MediaContent() throws Exception {} + + @Ignore("type missing") + @Test + public void test_MultiObject() throws Exception {} + + @Test + public void test_MediaContent_badStream() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(mediaContent); + objectOutput.flushBuffer(); + + byte[] byteArray = byteArrayOutputStream.toByteArray(); + for (int i = 0; i < byteArray.length; i++) { + if(i%3 == 0) { + byteArray[i] = (byte)~byteArray[i]; + } + } + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); + + try { + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + @SuppressWarnings("unused") // local variable, convenient for debug + Object read = deserialize.readObject(); + fail(); + } catch (JSONException expected) { + System.out.println(expected); + } + } + + @Test + public void test_MediaContent_WithType_badStream() throws Exception { + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(mediaContent); + objectOutput.flushBuffer(); + + byte[] byteArray = byteArrayOutputStream.toByteArray(); + for (int i = 0; i < byteArray.length; i++) { + if(i%3 == 0) { + byteArray[i] = (byte)~byteArray[i]; + } + } + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); + + try { + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + @SuppressWarnings("unused") // local variable, convenient for debug + Object read = deserialize.readObject(MediaContent.class); + fail(); + } catch (JSONException expected) { + System.out.println(expected); + } + } + + @Ignore + @Test(timeout=3000) + public void test_LoopReference() throws Exception {} + + // ========== Person + + @Ignore("person type missing") + @Test + public void test_Person() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_PersonList() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_PersonSet() throws Exception {} + + @Ignore("FastJson bug: com.alibaba.fastjson.JSONException: illegal identifier : 1") + @Test + public void test_IntPersonMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_StringPersonMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_StringPersonListMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_PersonListList() throws Exception {} + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/Hessian2SerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/Hessian2SerializationTest.java new file mode 100644 index 0000000000..84925f986d --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/Hessian2SerializationTest.java @@ -0,0 +1,229 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; +import java.util.Arrays; + +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.support.hessian.Hessian2Serialization; + +/** + * @author ding.lid + * + */ +public class Hessian2SerializationTest extends AbstractSerializationPersionFailTest { + { + serialization = new Hessian2Serialization(); + } + + // Hessian2 + + @Test + public void test_boolArray_withType() throws Exception { + boolean[] data = new boolean[] { true, false, true}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertTrue(Arrays.equals(data, (boolean[]) deserialize.readObject(boolean[].class))); + + try { + deserialize.readObject(boolean[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Ignore("type missing, char[] -> String") + @Test + public void test_charArray() throws Exception {} + + @Test + public void test_shortArray_withType() throws Exception { + short[] data = new short[] { 37, 39, 12 }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (short[]) deserialize.readObject(short[].class)); + + try { + deserialize.readObject(short[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Test + public void test_intArray_withType() throws Exception { + int[] data = new int[] { 234, 0, -1}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (int[]) deserialize.readObject()); + + try { + deserialize.readObject(int[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Test + public void test_longArray_withType() throws Exception { + long[] data = new long[] { 234, 0, -1}; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (long[]) deserialize.readObject()); + + try { + deserialize.readObject(long[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Test + public void test_floatArray_withType() throws Exception { + float[] data = new float[] { 37F, -3.14F, 123456.7F }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (float[]) deserialize.readObject(), 0.0001F); + + try { + deserialize.readObject(float[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Test + public void test_doubleArray_withType() throws Exception { + double[] data = new double[] { 37D, -3.14D, 123456.7D }; + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, (double[]) deserialize.readObject(double[].class), 0.0001); + + try { + deserialize.readObject(double[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Test + public void test_StringArray_withType() throws Exception { + + String[] data = new String[] { "1", "b" }; + + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject(data); + objectOutput.flushBuffer(); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + ObjectInput deserialize = serialization.deserialize(url, byteArrayInputStream); + + assertArrayEquals(data, deserialize.readObject(String[].class)); + + try { + deserialize.readObject(String[].class); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) {} + // NOTE: Hessian2抛出了ArrayIndexOutOfBoundsException 而不是 IOException!! + // 容忍这个问题!! + } + + @Ignore("type missing, Byte -> Integer") + @Test + public void test_ByteWrap() throws Exception { } + + + // FIXME + @Ignore("com.alibaba.com.caucho.hessian.io.HessianProtocolException: 'java.math.BigInteger' could not be instantiated") + @Test + public void test_BigInteger() throws Exception {} + + // FIXME + @Ignore("com.alibaba.com.caucho.hessian.io.HessianProtocolException: 'java.math.BigInteger' could not be instantiated") + @Test + public void test_BigInteger_withType() throws Exception {} + + // FIXME + @Ignore("Bad Stream read other type data") + @Test + public void test_MediaContent_badStream() throws Exception {} +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/JavaSerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/JavaSerializationTest.java new file mode 100644 index 0000000000..df0543ce6a --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/JavaSerializationTest.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import com.alibaba.dubbo.common.serialize.support.java.JavaSerialization; + +/** + * @author ding.lid + * + */ +public class JavaSerializationTest extends AbstractSerializationPersionFailTest { + { + serialization = new JavaSerialization(); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/JsonSerializationTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/JsonSerializationTest.java new file mode 100644 index 0000000000..7940f251f3 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/serialize/serialization/JsonSerializationTest.java @@ -0,0 +1,222 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.serialize.serialization; + +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.serialize.support.json.JsonSerialization; + +/** + * FIXME Json Serialization的失败,被暂时被忽略 + * + * @author ding.lid + * + */ +public class JsonSerializationTest extends AbstractSerializationPersionOkTest { + { + serialization = new JsonSerialization(); + } + + // FIXME + @Ignore + @Test + public void test_BytesRange() throws Exception {} + + @Ignore("bool[] type missing to List") + @Test + public void test_boolArray() throws Exception {} + + @Ignore("char[] type missing to List") + @Test + public void test_charArray() throws Exception {} + + @Ignore("short[] type missing to List") + @Test + public void test_shortArray() throws Exception {} + + @Ignore("int[] type missing to List") + @Test + public void test_intArray() throws Exception {} + + @Ignore("long[] type missing to List") + @Test + public void test_longArray() throws Exception {} + + @Ignore + @Test + public void test_floatArray() throws Exception {} + + @Ignore + @Test + public void test_doubleArray() throws Exception {} + + @Ignore("String[] type missing to List") + @Test + public void test_StringArray() throws Exception {} + + @Ignore("Integer[] type missing to List") + @Test + public void test_IntegerArray() throws Exception {} + + @Ignore + @Test + public void test_EnumArray() throws Exception {} + + @Ignore + @Test + public void test_Date() throws Exception {} + + @Ignore("毫秒部分丢失成0") + @Test + public void test_Date_withType() throws Exception {} + + @Ignore + @Test + public void test_Time() throws Exception {} + + @Ignore + @Test + public void test_Time_withType() throws Exception {} + + @Ignore("Byte type missing to Long") + @Test + public void test_ByteWrap() throws Exception {} + + @Ignore("BigInteger type missing to Long") + @Test + public void test_BigInteger() throws Exception {} + + @Ignore + @Test + public void test_BigDecimal() throws Exception {} + + @Ignore + @Test + public void test_BigDecimal_withType() throws Exception {} + + @Ignore("BizException type missing") + @Test + public void test_BizException() throws Exception {} + + @Ignore("BizExceptionNoDefaultConstructor type missing") + @Test + public void test_BizExceptionNoDefaultConstructor() throws Exception {} + + @Ignore("NoDefaultConstructor") + @Test + public void test_BizExceptionNoDefaultConstructor_WithType() throws Exception {} + + @Ignore("Enum type missing") + @Test + public void test_enum() throws Exception {} + + @Ignore("Set type missing to Map") + @Test + public void test_StringSet() throws Exception {} + + @Ignore("LinkedHashMap type missing to Map") + @Test + public void test_LinkedHashMap() throws Exception {} + + // + + @Ignore("SPerson type missing") + @Test + public void test_SPerson() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_SPersonList() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_SPersonSet() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_IntSPersonMap() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_StringSPersonMap() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_StringSPersonListMap() throws Exception {} + + @Ignore("SPerson type missing") + @Test + public void test_SPersonListList() throws Exception {} + + @Ignore("type missing") + @Test + public void test_BigPerson() throws Exception {} + + @Ignore("type missing") + @Test + public void test_BigPerson_WithType() throws Exception {} + + @Ignore("type missing") + @Test + public void test_MediaContent() throws Exception {} + + @Ignore("type missing") + @Test + public void test_MediaContent_WithType() throws Exception {} + + @Ignore("type missing") + @Test + public void test_MultiObject() throws Exception {} + + @Ignore("type missing") + @Test + public void test_MultiObject_WithType() throws Exception {} + + @Ignore + @Test + public void test_LoopReference() throws Exception {} + + // Person + + @Ignore("person type missing") + @Test + public void test_Person() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_PersonList() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_PersonSet() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_IntPersonMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_StringPersonMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_StringPersonListMap() throws Exception {} + + @Ignore("person type missing") + @Test + public void test_PersonListList() throws Exception {} +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/AtomicPositiveIntegerTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/AtomicPositiveIntegerTest.java new file mode 100644 index 0000000000..239e59a7b1 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/AtomicPositiveIntegerTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import org.junit.Test; + +/** + * @author ding.lid + */ +public class AtomicPositiveIntegerTest { + AtomicPositiveInteger i1 = new AtomicPositiveInteger(); + + AtomicPositiveInteger i2 = new AtomicPositiveInteger(127); + + AtomicPositiveInteger i3 = new AtomicPositiveInteger(Integer.MAX_VALUE); + + @Test + public void test_get() throws Exception { + assertEquals(0, i1.get()); + assertEquals(127, i2.get()); + assertEquals(Integer.MAX_VALUE, i3.get()); + } + + @Test + public void test_set() throws Exception { + i1.set(100); + assertEquals(100, i1.get()); + + try { + i1.set(-1); + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), + allOf(containsString("new value"), containsString("< 0"))); + } + } + + @Test + public void test_getAndIncrement() throws Exception { + int get = i1.getAndIncrement(); + assertEquals(0, get); + assertEquals(1, i1.get()); + + get = i2.getAndIncrement(); + assertEquals(127, get); + assertEquals(128, i2.get()); + + get = i3.getAndIncrement(); + assertEquals(Integer.MAX_VALUE, get); + assertEquals(0, i3.get()); + } + + @Test + public void test_getAndDecrement() throws Exception { + int get = i1.getAndDecrement(); + assertEquals(0, get); + assertEquals(Integer.MAX_VALUE, i1.get()); + + get = i2.getAndDecrement(); + assertEquals(127, get); + assertEquals(126, i2.get()); + + get = i3.getAndDecrement(); + assertEquals(Integer.MAX_VALUE, get); + assertEquals(Integer.MAX_VALUE - 1, i3.get()); + } + + @Test + public void test_incrementAndGet() throws Exception { + int get = i1.incrementAndGet(); + assertEquals(1, get); + assertEquals(1, i1.get()); + + get = i2.incrementAndGet(); + assertEquals(128, get); + assertEquals(128, i2.get()); + + get = i3.incrementAndGet(); + assertEquals(0, get); + assertEquals(0, i3.get()); + } + + @Test + public void test_decrementAndGet() throws Exception { + int get = i1.decrementAndGet(); + assertEquals(Integer.MAX_VALUE, get); + assertEquals(Integer.MAX_VALUE, i1.get()); + + get = i2.decrementAndGet(); + assertEquals(126, get); + assertEquals(126, i2.get()); + + get = i3.decrementAndGet(); + assertEquals(Integer.MAX_VALUE - 1, get); + assertEquals(Integer.MAX_VALUE - 1, i3.get()); + } + + @Test + public void test_getAndSet() throws Exception { + int get = i1.getAndSet(100); + assertEquals(0, get); + assertEquals(100, i1.get()); + + try { + i1.getAndSet(-1); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), + allOf(containsString("new value"), containsString("< 0"))); + } + } + + @Test + public void test_getAndAnd() throws Exception { + int get = i1.getAndAdd(3); + assertEquals(0, get); + assertEquals(3, i1.get()); + + get = i2.getAndAdd(3); + assertEquals(127, get); + assertEquals(127 + 3, i2.get()); + + get = i3.getAndAdd(3); + assertEquals(Integer.MAX_VALUE, get); + assertEquals(2, i3.get()); + } + + + @Test + public void test_addAndGet() throws Exception { + int get = i1.addAndGet(3); + assertEquals(3, get); + assertEquals(3, i1.get()); + + get = i2.addAndGet(3); + assertEquals(127 + 3, get); + assertEquals(127 + 3, i2.get()); + + get = i3.addAndGet(3); + assertEquals(2, get); + assertEquals(2, i3.get()); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/CollectionUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/CollectionUtilsTest.java new file mode 100644 index 0000000000..216f90fc96 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/CollectionUtilsTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +/** + * @author ding.lid + */ +public class CollectionUtilsTest { + @Test + public void test_sort() throws Exception { + List list = new ArrayList(); + list.add(100); + list.add(10); + list.add(20); + + List expected = new ArrayList(); + expected.add(10); + expected.add(20); + expected.add(100); + + assertEquals(expected, CollectionUtils.sort(list)); + } + + @Test + public void test_sort_null() throws Exception { + assertNull(CollectionUtils.sort(null)); + + assertTrue(CollectionUtils.sort(new ArrayList()).isEmpty()); + } + + @Test + public void test_sortSimpleName() throws Exception { + List list = new ArrayList(); + list.add("aaa.z"); + list.add("b"); + list.add(null); + list.add("zzz.a"); + list.add("c"); + list.add(null); + + List sorted = CollectionUtils.sortSimpleName(list); + assertNull(sorted.get(0)); + assertNull(sorted.get(1)); + } + + @Test + public void test_sortSimpleName_null() throws Exception { + assertNull(CollectionUtils.sortSimpleName(null)); + + assertTrue(CollectionUtils.sortSimpleName(new ArrayList()).isEmpty()); + } + + @Test + public void test_splitAll() throws Exception { + assertNull(CollectionUtils.splitAll(null, null)); + assertNull(CollectionUtils.splitAll(null, "-")); + + assertTrue(CollectionUtils.splitAll(new HashMap>(), "-").isEmpty()); + + Map> input = new HashMap>(); + input.put("key1", Arrays.asList("1:a", "2:b", "3:c")); + input.put("key2", Arrays.asList("1:a", "2:b")); + input.put("key3", null); + input.put("key4", new ArrayList()); + + Map> expected = new HashMap>(); + expected.put("key1", CollectionUtils.toStringMap("1", "a", "2", "b", "3", "c")); + expected.put("key2", CollectionUtils.toStringMap("1", "a", "2", "b")); + expected.put("key3", null); + expected.put("key4", new HashMap()); + + assertEquals(expected, CollectionUtils.splitAll(input, ":")); + } + + @Test + public void test_joinAll() throws Exception { + assertNull(CollectionUtils.joinAll(null, null)); + assertNull(CollectionUtils.joinAll(null, "-")); + + Map> expected = new HashMap>(); + expected.put("key1", Arrays.asList("1:a", "2:b", "3:c")); + expected.put("key2", Arrays.asList("1:a", "2:b")); + expected.put("key3", null); + expected.put("key4", new ArrayList()); + + Map> input = new HashMap>(); + input.put("key1", CollectionUtils.toStringMap("1", "a", "2", "b", "3", "c")); + input.put("key2", CollectionUtils.toStringMap("1", "a", "2", "b")); + input.put("key3", null); + input.put("key4", new HashMap()); + + Map> output = CollectionUtils.joinAll(input, ":"); + for (Map.Entry> entry : output.entrySet()) { + if (entry.getValue() == null) + continue; + Collections.sort(entry.getValue()); + } + + assertEquals(expected, output); + } + + @Test + public void test_mapEquals() throws Exception { + assertTrue(CollectionUtils.mapEquals(null, null)); + assertFalse(CollectionUtils.mapEquals(null, new HashMap())); + assertFalse(CollectionUtils.mapEquals(new HashMap(), null)); + + assertTrue(CollectionUtils.mapEquals(CollectionUtils.toStringMap("1", "a", "2", "b"), CollectionUtils.toStringMap("1", "a", "2", "b"))); + assertFalse(CollectionUtils.mapEquals(CollectionUtils.toStringMap("1", "a"), CollectionUtils.toStringMap("1", "a", "2", "b"))); + } + + @Test + public void test_toMap() throws Exception { + assertTrue(CollectionUtils.toMap().isEmpty()); + + + Map expected = new HashMap(); + expected.put("a", 1); + expected.put("b", 2); + expected.put("c", 3); + + assertEquals(expected, CollectionUtils.toMap("a", 1, "b", 2, "c", 3)); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/CompatibleTypeUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/CompatibleTypeUtilsTest.java new file mode 100644 index 0000000000..61bf5ce303 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/CompatibleTypeUtilsTest.java @@ -0,0 +1,168 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import java.util.Date; + +import org.junit.Test; + +public class CompatibleTypeUtilsTest { + + @Test + public void testIsIntegerLikeType() { + Class[] types = { byte.class, Byte.class, short.class, Short.class, int.class, + Integer.class, long.class, Long.class, }; + + for (Class c : types) { + assertTrue(CompatibleTypeUtils.isIntegerLikeType(c)); + } + + assertFalse(CompatibleTypeUtils.isIntegerLikeType(double.class)); + assertFalse(CompatibleTypeUtils.isIntegerLikeType(Date.class)); + } + + @Test + public void testIsFloatLikeType() { + Class[] types = { float.class, Float.class, double.class, Double.class }; + + for (Class c : types) { + assertTrue(CompatibleTypeUtils.isFloatLikeType(c)); + } + + assertFalse(CompatibleTypeUtils.isFloatLikeType(int.class)); + assertFalse(CompatibleTypeUtils.isFloatLikeType(Date.class)); + } + + @Test + public void testConvertIntegerLikeType() { + { + Object v = CompatibleTypeUtils.convertIntegerLikeType(3, byte.class); + assertEquals((byte) 3, ((Byte) v).byteValue()); + } + { + Object v = CompatibleTypeUtils.convertIntegerLikeType(3L, Short.class); + assertEquals((short) 3, ((Short) v).shortValue()); + } + { + Object v = CompatibleTypeUtils.convertIntegerLikeType((short) 3, int.class); + assertEquals(3, ((Integer) v).intValue()); + } + { + Object v = CompatibleTypeUtils.convertIntegerLikeType((short) 3, long.class); + assertEquals(Long.class, v.getClass()); + assertEquals(3L, ((Long) v).longValue()); + } + { + Object v = CompatibleTypeUtils.convertIntegerLikeType((short) 3, Long.class); + assertEquals(Long.class, v.getClass()); + assertEquals(3L, ((Long) v).longValue()); + } + } + + @Test + public void testConvertFloatLikeType() { + { + Object v = CompatibleTypeUtils.convertFloatLikeType(3D, float.class); + assertEquals(Float.class, v.getClass()); + assertEquals(3F, ((Float) v).floatValue(), 0); + } + { + Object v = CompatibleTypeUtils.convertFloatLikeType(3F, double.class); + assertEquals(Double.class, v.getClass()); + assertEquals(3D, ((Double) v).doubleValue(), 0); + } + { + Object v = CompatibleTypeUtils.convertFloatLikeType(3F, Double.class); + assertEquals(Double.class, v.getClass()); + assertEquals(3D, ((Double) v).doubleValue(), 0); + } + } + + @Test + public void testIsCharType() { + Class[] types = { char.class, Character.class, }; + + for (Class c : types) { + assertTrue(CompatibleTypeUtils.isCharType(c)); + } + + assertFalse(CompatibleTypeUtils.isCharType(double.class)); + assertFalse(CompatibleTypeUtils.isCharType(Date.class)); + } + + @Test + public void testCovert2Char() { + Character c = CompatibleTypeUtils.covert2Char("a"); + assertEquals(Character.valueOf('a'), c); + } + + @Test + public void testCovert2Char_exception_moreChar() { + try { + CompatibleTypeUtils.covert2Char("ab"); + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), containsString("the String MUST only 1 char")); + } + } + + @Test + public void testNeedCompatibleTypeConvert() { + assertTrue(CompatibleTypeUtils.needCompatibleTypeConvert("abc", char.class)); + assertTrue(CompatibleTypeUtils.needCompatibleTypeConvert(3L, int.class)); + assertTrue(CompatibleTypeUtils.needCompatibleTypeConvert(3F, double.class)); + + // 类型参数为null时,要返回False + assertFalse(CompatibleTypeUtils.needCompatibleTypeConvert("a", null)); + + assertFalse(CompatibleTypeUtils.needCompatibleTypeConvert(null, String.class)); + assertFalse(CompatibleTypeUtils.needCompatibleTypeConvert(null, int.class)); + assertFalse(CompatibleTypeUtils.needCompatibleTypeConvert(null, Date.class)); + + assertFalse(CompatibleTypeUtils.needCompatibleTypeConvert("abc", String.class)); + assertTrue(CompatibleTypeUtils.needCompatibleTypeConvert("abc", Date.class)); + assertFalse(CompatibleTypeUtils.needCompatibleTypeConvert(3D, Double.class)); + } + + @Test + public void testCompatibleTypeConvert() { + { + Object v = CompatibleTypeUtils.compatibleTypeConvert("a", char.class); + assertEquals(Character.valueOf('a'), (Character) v); + } + { + Object v = CompatibleTypeUtils.compatibleTypeConvert(3L, int.class); + assertEquals(Integer.valueOf(3), (Integer) v); + } + { + Object v = CompatibleTypeUtils.compatibleTypeConvert(3F, Double.class); + assertEquals(Double.valueOf(3), (Double) v, 0); + } + { + Object input = new Object(); + Object v = CompatibleTypeUtils.compatibleTypeConvert(input, Date.class); + assertSame(input, v); + } + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/NetUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/NetUtilsTest.java new file mode 100644 index 0000000000..fcf12f3312 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/NetUtilsTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import junit.framework.Assert; +import junit.framework.TestCase; + +public class NetUtilsTest extends TestCase { + + public void testValidAddress() throws Exception { + Assert.assertTrue(NetUtils.isValidAddress("10.20.130.230:20880")); + Assert.assertFalse(NetUtils.isValidAddress("10.20.130.230")); + Assert.assertFalse(NetUtils.isValidAddress("10.20.130.230:666666")); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ParametersTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ParametersTest.java new file mode 100644 index 0000000000..ae006af601 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ParametersTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +public class ParametersTest extends TestCase +{ + final String ServiceName = "com.alibaba.dubbo.rpc.service.GenericService"; + final String ServiceVersion = "1.0.15"; + final String LoadBalance = "lcr"; + + public void testMap2Parameters() throws Exception + { + Map map = new HashMap(); + map.put("name", "com.alibaba.dubbo.rpc.service.GenericService"); + map.put("version", "1.0.15"); + map.put("lb", "lcr"); + map.put("max.active", "500"); + assertEquals(map.get("name"), ServiceName); + assertEquals(map.get("version"), ServiceVersion); + assertEquals(map.get("lb"), LoadBalance); + } + + public void testString2Parameters() throws Exception + { + String qs = "name=com.alibaba.dubbo.rpc.service.GenericService&version=1.0.15&lb=lcr"; + Map map = StringUtils.parseQueryString(qs); + assertEquals(map.get("name"), ServiceName); + assertEquals(map.get("version"), ServiceVersion); + assertEquals(map.get("lb"), LoadBalance); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/PojoUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/PojoUtilsTest.java new file mode 100644 index 0000000000..b2d6c29126 --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/PojoUtilsTest.java @@ -0,0 +1,244 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.model.Person; +import com.alibaba.dubbo.common.model.SerializablePerson; +import com.alibaba.dubbo.common.model.person.BigPerson; +import com.alibaba.dubbo.common.model.person.FullAddress; +import com.alibaba.dubbo.common.model.person.PersonInfo; +import com.alibaba.dubbo.common.model.person.PersonStatus; +import com.alibaba.dubbo.common.model.person.Phone; + +/** + * @author ding.lid + */ +public class PojoUtilsTest { + + public void assertObject(Object data) { + Object generalize = PojoUtils.generalize(data); + Object realize = PojoUtils.realize(generalize, data.getClass()); + assertEquals(data, realize); + } + + public void assertArrayObject(T[] data) { + Object generalize = PojoUtils.generalize(data); + @SuppressWarnings("unchecked") + T[] realize = (T[]) PojoUtils.realize(generalize, data.getClass()); + assertArrayEquals(data, realize); + } + + @Test + public void test_primitive() throws Exception { + assertObject(Boolean.TRUE); + assertObject(Boolean.FALSE); + + assertObject(Byte.valueOf((byte) 78)); + + assertObject('a'); + assertObject('中'); + + assertObject(Short.valueOf((short) 37)); + + assertObject(78); + + assertObject(123456789L); + + assertObject(3.14F); + assertObject(3.14D); + } + + @Test + public void test_pojo() throws Exception { + assertObject(new Person()); + assertObject(new SerializablePerson()); + } + + @Test + public void test_PrimitiveArray() throws Exception { + assertObject(new boolean[] { true, false }); + assertObject(new Boolean[] { true, false, true }); + + assertObject(new byte[] { 1, 12, 28, 78 }); + assertObject(new Byte[] { 1, 12, 28, 78 }); + + assertObject(new char[] { 'a', '中', '无' }); + assertObject(new Character[] { 'a', '中', '无' }); + + assertObject(new short[] { 37, 39, 12 }); + assertObject(new Short[] { 37, 39, 12 }); + + assertObject(new int[] { 37, -39, 12456 }); + assertObject(new Integer[] { 37, -39, 12456 }); + + assertObject(new long[] { 37L, -39L, 123456789L }); + assertObject(new Long[] { 37L, -39L, 123456789L }); + + assertObject(new float[] { 37F, -3.14F, 123456.7F }); + assertObject(new Float[] { 37F, -39F, 123456.7F }); + + assertObject(new double[] { 37D, -3.14D, 123456.7D }); + assertObject(new Double[] { 37D, -39D, 123456.7D}); + + + assertArrayObject(new Boolean[] { true, false, true }); + + assertArrayObject(new Byte[] { 1, 12, 28, 78 }); + + assertArrayObject(new Character[] { 'a', '中', '无' }); + + assertArrayObject(new Short[] { 37, 39, 12 }); + + assertArrayObject(new Integer[] { 37, -39, 12456 }); + + assertArrayObject(new Long[] { 37L, -39L, 123456789L }); + + assertArrayObject(new Float[] { 37F, -39F, 123456.7F }); + + assertArrayObject(new Double[] { 37D, -39D, 123456.7D}); + } + + @Test + public void test_PojoArray() throws Exception { + Person[] array = new Person[2]; + array[0] = new Person(); + { + Person person = new Person(); + person.setName("xxxx"); + array[1] = person; + } + assertArrayObject(array); + } + + // FIXME + @Ignore("Type missing, Person -> Map") + @Test + public void test_simpleCollection() throws Exception { + List list = new ArrayList(); + list.add(new Person()); + { + Person person = new Person(); + person.setName("xxxx"); + list.add(person); + } + assertObject(list); + } + + BigPerson bigPerson; + { + bigPerson = new BigPerson(); + bigPerson.setPersonId("id1"); + bigPerson.setLoginName("name1"); + bigPerson.setStatus(PersonStatus.ENABLED); + bigPerson.setEmail("abc@123.com"); + bigPerson.setPenName("pname"); + + ArrayList phones = new ArrayList(); + Phone phone1 = new Phone("86", "0571", "11223344", "001"); + Phone phone2 = new Phone("86", "0571", "11223344", "002"); + phones.add(phone1); + phones.add(phone2); + + PersonInfo pi = new PersonInfo(); + pi.setPhones(phones); + Phone fax = new Phone("86", "0571", "11223344", null); + pi.setFax(fax); + FullAddress addr = new FullAddress("CN", "zj", "1234", "Road1", "333444"); + pi.setFullAddress(addr); + pi.setMobileNo("1122334455"); + pi.setMale(true); + pi.setDepartment("b2b"); + pi.setHomepageUrl("www.abc.com"); + pi.setJobTitle("dev"); + pi.setName("name2"); + + bigPerson.setInfoProfile(pi); + } + + // FIXME + @Ignore("Type missing, List -> List") + @Test + public void test_total() throws Exception { + Object generalize = PojoUtils.generalize(bigPerson); + Object realize = PojoUtils.realize(generalize, BigPerson.class); + assertEquals(bigPerson, realize); + } + + // FIXME + @Ignore("Type missing, List -> List") + @Test + public void test_total_Array() throws Exception { + Object[] persons = new Object[] { bigPerson, bigPerson, bigPerson }; + + Object generalize = PojoUtils.generalize(persons); + Object[] realize = (Object[]) PojoUtils.realize(generalize, Object[].class); + assertArrayEquals(persons, realize); + } + + public static > T min(T[] arr) { + if (arr == null || arr.length == 0) + return null; + + T smallest = arr[0]; + for (int i = 1; i < arr.length; ++i) { + if (smallest.compareTo(arr[i]) > 0) { + smallest = arr[i]; + } + } + return smallest; + } + + public static > T min2(T[] arr) { + if (arr == null || arr.length == 0) + return null; + + T smallest = arr[0]; + for (int i = 1; i < arr.length; ++i) { + if (smallest.compareTo(arr[i]) > 0) { + smallest = arr[i]; + } + } + return smallest; + } + + public static & Serializable> T max(T[] arr) { + if (arr == null || arr.length == 0) + return null; + + T biggest = arr[0]; + for (int i = 1; i < arr.length; ++i) { + if (biggest.compareTo(arr[i]) < 0) { + biggest = arr[i]; + } + } + return biggest; + } + + public static & Serializable> T max2(Comparable[] arr) { + return null; + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ReflectUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ReflectUtilsTest.java new file mode 100644 index 0000000000..e81115420f --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/ReflectUtilsTest.java @@ -0,0 +1,172 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.containsString; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Test; + +public class ReflectUtilsTest extends TestCase +{ + public void testIsCompatible() throws Exception + { + assertEquals(ReflectUtils.isCompatible(short.class, (short)1), true); + assertEquals(ReflectUtils.isCompatible(int.class, 1), true); + assertEquals(ReflectUtils.isCompatible(double.class, 1.2), true); + assertEquals(ReflectUtils.isCompatible(Object.class, 1.2), true); + assertEquals(ReflectUtils.isCompatible(List.class, new ArrayList()), true); + } + + public void testNameDesc() throws Exception + { + // getName + assertEquals("boolean", ReflectUtils.getName(boolean.class)); + assertEquals("int[][][]", ReflectUtils.getName(int[][][].class)); + assertEquals("java.lang.Object[][]", ReflectUtils.getName(Object[][].class)); + + // getDesc + assertEquals("Z", ReflectUtils.getDesc(boolean.class)); + assertEquals("[[[I", ReflectUtils.getDesc(int[][][].class)); + assertEquals("[[Ljava/lang/Object;", ReflectUtils.getDesc(Object[][].class)); + + // name2desc + assertEquals("Z", ReflectUtils.name2desc(ReflectUtils.getName(boolean.class))); + assertEquals("[[[I", ReflectUtils.name2desc(ReflectUtils.getName(int[][][].class))); + assertEquals("[[Ljava/lang/Object;", ReflectUtils.name2desc(ReflectUtils.getName(Object[][].class))); + + // desc2name + assertEquals("short[]", ReflectUtils.desc2name(ReflectUtils.getDesc(short[].class))); + assertEquals("int", ReflectUtils.desc2name(ReflectUtils.getDesc(int.class))); + assertEquals("java.lang.Object[][]", ReflectUtils.desc2name(ReflectUtils.getDesc(Object[][].class))); + } + + public void testName2Class() throws Exception + { + assertEquals(boolean.class, ReflectUtils.name2class("boolean")); + assertEquals(boolean[].class, ReflectUtils.name2class("boolean[]")); + assertEquals(int[][].class, ReflectUtils.name2class(ReflectUtils.getName(int[][].class))); + assertEquals(ReflectUtilsTest[].class, ReflectUtils.name2class(ReflectUtils.getName(ReflectUtilsTest[].class))); + } + + public void testDesc2Class() throws Exception + { + assertEquals(boolean.class, ReflectUtils.desc2class("Z")); + assertEquals(boolean[].class, ReflectUtils.desc2class("[Z")); + assertEquals(int[][].class, ReflectUtils.desc2class(ReflectUtils.getDesc(int[][].class))); + assertEquals(ReflectUtilsTest[].class, ReflectUtils.desc2class(ReflectUtils.getDesc(ReflectUtilsTest[].class))); + + String desc; + Class[] cs; + + cs = new Class[]{ int.class, getClass(), String.class, int[][].class, boolean[].class }; + desc = ReflectUtils.getDesc(cs); + assertSame(cs, ReflectUtils.desc2classArray(desc)); + + cs = new Class[]{}; + desc = ReflectUtils.getDesc(cs); + assertSame(cs, ReflectUtils.desc2classArray(desc)); + + cs = new Class[]{ void.class, String[].class, int[][].class, ReflectUtilsTest[][].class }; + desc = ReflectUtils.getDesc(cs); + assertSame(cs, ReflectUtils.desc2classArray(desc)); + } + + protected void assertSame(Class[] cs1, Class[] cs2) throws Exception + { + assertEquals(cs1.length, cs2.length); + for(int i=0;i[] parameterTypes = m.getParameterTypes(); + assertEquals(1, parameterTypes.length); + assertEquals(int.class, parameterTypes[0]); + } + + @Test + public void test_findMethodByMethodSignature_override() throws Exception { + { + Method m = ReflectUtils.findMethodByMethodSignature(TestedClass.class, + "overrideMethod", new String[] {"int"}); + + assertEquals("overrideMethod", m.getName()); + Class[] parameterTypes = m.getParameterTypes(); + assertEquals(1, parameterTypes.length); + assertEquals(int.class, parameterTypes[0]); + } + { + Method m = ReflectUtils.findMethodByMethodSignature(TestedClass.class, + "overrideMethod", new String[] {"java.lang.Integer"}); + + assertEquals("overrideMethod", m.getName()); + Class[] parameterTypes = m.getParameterTypes(); + assertEquals(1, parameterTypes.length); + assertEquals(Integer.class, parameterTypes[0]); + } + } + + @Test + public void test_findMethodByMethodSignature_override_Morethan1() throws Exception { + try { + ReflectUtils.findMethodByMethodSignature(TestedClass.class, "overrideMethod", null); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected.getMessage(), containsString( + "Not unique method for method name(")); + } + } + + @Test + public void test_findMethodByMethodSignature_notFound() throws Exception { + try { + ReflectUtils.findMethodByMethodSignature(TestedClass.class, "notExsited", null); + fail(); + } catch (NoSuchMethodException expected) { + assertThat(expected.getMessage(), containsString("No such method ")); + assertThat(expected.getMessage(), containsString("in class")); + } + } + + static class TestedClass { + public void method1(int x) { + } + + public void overrideMethod(int x) { + } + + public void overrideMethod(Integer x) { + } + + public void overrideMethod(String s) { + } + + public void overrideMethod(String s1, String s2) { + } + } + +} \ No newline at end of file diff --git a/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/StringUtilsTest.java b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/StringUtilsTest.java new file mode 100644 index 0000000000..a5f385334e --- /dev/null +++ b/dubbo-common/src/test/java/com/alibaba/dubbo/common/utils/StringUtilsTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.common.utils; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +public class StringUtilsTest extends TestCase +{ + public void testJoin() throws Exception + { + String[] s = {"1","2","3"}; + assertEquals(StringUtils.join(s), "123"); + assertEquals(StringUtils.join(s, ','), "1,2,3"); + } + + public void testSplit() throws Exception + { + String s = "d,1,2,4"; + assertEquals(StringUtils.split(s, ',').length, 4); + } + + public void testTranslat() throws Exception + { + String s = "16314"; + assertEquals(StringUtils.translat(s, "123456", "abcdef"), "afcad"); + assertEquals(StringUtils.translat(s, "123456", "abcd"), "acad"); + } + + public void testJoin_Colletion_String() throws Exception + { + List list = new ArrayList(); + assertEquals("", StringUtils.join(list, ",")); + + list.add("v1"); + assertEquals("v1", StringUtils.join(list, "-")); + + list.add("v2"); + list.add("v3"); + String out = StringUtils.join(list, ":"); + assertEquals("v1:v2:v3", out); + } +} \ No newline at end of file diff --git a/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext1.Ext1 b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext1.Ext1 new file mode 100644 index 0000000000..7cfd485723 --- /dev/null +++ b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext1.Ext1 @@ -0,0 +1,3 @@ +com.alibaba.dubbo.common.extensionloader.ext1.impl.Ext1Impl1 +com.alibaba.dubbo.common.extensionloader.ext1.impl.Ext1Impl2 +com.alibaba.dubbo.common.extensionloader.ext1.impl.Ext1Impl3 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext2.Ext2 b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext2.Ext2 new file mode 100644 index 0000000000..c58f1e4304 --- /dev/null +++ b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext2.Ext2 @@ -0,0 +1,3 @@ +com.alibaba.dubbo.common.extensionloader.ext2.impl.Ext2Impl1 +com.alibaba.dubbo.common.extensionloader.ext2.impl.Ext2Impl2 +com.alibaba.dubbo.common.extensionloader.ext2.impl.Ext2Impl3 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext3.Ext3 b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext3.Ext3 new file mode 100644 index 0000000000..b0e93dcf3f --- /dev/null +++ b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext3.Ext3 @@ -0,0 +1,3 @@ +com.alibaba.dubbo.common.extensionloader.ext3.impl.Ext3Impl1 +com.alibaba.dubbo.common.extensionloader.ext3.impl.Ext3Impl2 +com.alibaba.dubbo.common.extensionloader.ext3.impl.Ext3Impl3 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext4.Ext4 b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext4.Ext4 new file mode 100644 index 0000000000..a70b49d813 --- /dev/null +++ b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext4.Ext4 @@ -0,0 +1,2 @@ +com.alibaba.dubbo.common.extensionloader.ext4.impl.Ext4Impl1 +com.alibaba.dubbo.common.extensionloader.ext4.impl.Ext4Impl2 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod new file mode 100644 index 0000000000..8010ca6859 --- /dev/null +++ b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext5.Ext5NoAdaptiveMethod @@ -0,0 +1,4 @@ +com.alibaba.dubbo.common.extensionloader.ext5.impl.Ext5Impl1 +com.alibaba.dubbo.common.extensionloader.ext5.impl.Ext5Impl2 +com.alibaba.dubbo.common.extensionloader.ext5.impl.Ext5AutoProxy1 +com.alibaba.dubbo.common.extensionloader.ext5.impl.Ext5AutoProxy2 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext6_inject.Ext6 b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext6_inject.Ext6 new file mode 100644 index 0000000000..6dd3b3c110 --- /dev/null +++ b/dubbo-common/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extensionloader.ext6_inject.Ext6 @@ -0,0 +1,2 @@ +com.alibaba.dubbo.common.extensionloader.ext6_inject.impl.Ext6Impl1 +com.alibaba.dubbo.common.extensionloader.ext6_inject.impl.Ext6Impl2 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/StreamUtilsTest.txt b/dubbo-common/src/test/resources/StreamUtilsTest.txt new file mode 100644 index 0000000000..ad471007bd --- /dev/null +++ b/dubbo-common/src/test/resources/StreamUtilsTest.txt @@ -0,0 +1 @@ +0123456789 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/com/alibaba/dubbo/common/serialize/dubbo/SimpleDO.fc b/dubbo-common/src/test/resources/com/alibaba/dubbo/common/serialize/dubbo/SimpleDO.fc new file mode 100644 index 0000000000..c8c083c17e --- /dev/null +++ b/dubbo-common/src/test/resources/com/alibaba/dubbo/common/serialize/dubbo/SimpleDO.fc @@ -0,0 +1,2 @@ +a,d,e,b,c +str3,str2 \ No newline at end of file diff --git a/dubbo-common/src/test/resources/log4j.xml b/dubbo-common/src/test/resources/log4j.xml new file mode 100644 index 0000000000..ae988c35f1 --- /dev/null +++ b/dubbo-common/src/test/resources/log4j.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/pom.xml b/dubbo-config/pom.xml new file mode 100644 index 0000000000..e940fb5acf --- /dev/null +++ b/dubbo-config/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-config + jar + Dubbo Config Module + The config module of dubbo project + + + com.alibaba + dubbo-registry + ${project.parent.version} + + + com.alibaba + dubbo-monitor + ${project.parent.version} + + + org.springframework + spring + + + + + + org.codehaus.mojo + wagon-maven-plugin + 1.0-beta-3 + + + upload-schema + deploy + + upload-single + + + ${basedir}/src/main/resources/com/alibaba/dubbo/config/spring/schema/dubbo.xsd + dav:http://code.alibabatech.com/schema/dubbo/ + code.alibabatech.com + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java new file mode 100644 index 0000000000..e39f7e9a2f --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractConfig.java @@ -0,0 +1,305 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.io.InputStream; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URLEncoder; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.rpc.RpcConstants; + +/** + * AbstractConfig + * + * @author william.liangf + */ +public abstract class AbstractConfig implements Serializable { + + private static final long serialVersionUID = 4267533505537413570L; + + protected static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class); + + private static final Properties PROPERTIES = loadProperties(); + + private static final int MAX_LENGTH = 100; + + private static final int MAX_PATH_LENGTH = 200; + + private static final Pattern PATTERN_PATH = Pattern.compile("[\\-._/0-9a-zA-Z]+"); + + private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[\\-._,0-9a-zA-Z]+"); + + private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*"); + + private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+"); + + private static final Pattern PATTERN_NAME_HAS_COLON= Pattern.compile("[:\\-._0-9a-zA-Z]+"); + + protected static String getLegacyProperty(String key) { + String value = System.getProperty(key); + if (value == null || value.length() == 0) { + value = PROPERTIES.getProperty(key); + } + return value; + } + + public static void mergeProperties(Properties properties) { + if (properties != null) { + PROPERTIES.putAll(properties); + } + } + + private static Properties loadProperties() { + Properties properties = new Properties(); + try { + InputStream input = Thread.currentThread().getContextClassLoader() + .getResourceAsStream("dubbo.properties"); + if (input != null) { + try { + properties.load(input); + } finally { + input.close(); + } + } + } catch (Throwable e) { + logger.warn("Fail to load dubbo.properties file: " + e.getMessage(), e); + } + return properties; + } + + private static final Pattern GROUP_AND_VERION = Pattern.compile("^[\\-.0-9_a-zA-Z]+(\\:[\\-.0-9_a-zA-Z]+)?$"); + + protected static String convertMonitor(String monitor, URL registry) { + if (monitor == null || monitor.length() == 0) { + return null; + } + if (GROUP_AND_VERION.matcher(monitor).matches()) { + String group; + String version; + int i = monitor.indexOf(':'); + if (i > 0) { + group = monitor.substring(0, i); + version = monitor.substring(i + 1); + } else { + group = monitor; + version = "0.0.0"; + } + monitor = registry.setProtocol("dubbo").addParameter(Constants.MONITOR_KEY, registry.getProtocol()).addParameterAndEncoded(RpcConstants.REFER_KEY, "group=" + group + "&version=" + version + "&interface=" + MonitorService.class.getName()).toFullString(); + } + try { + return URLEncoder.encode(monitor, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + protected static void appendParameters(Map parameters, Object config) { + appendParameters(parameters, config, null); + } + + protected static void appendParameters(Map parameters, Object config, String prefix) { + appendMaps(parameters, config, prefix, false); + } + + protected static void appendAttributes(Map parameters, Object config) { + appendAttributes(parameters, config, null); + } + + protected static void appendAttributes(Map parameters, Object config, String prefix) { + appendMaps(parameters, config, prefix, true); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static void appendMaps(Map parameters, Object config, String prefix, boolean attribute) { + if (config == null) { + return; + } + Method[] methods = config.getClass().getMethods(); + for (Method method : methods) { + try { + String name = method.getName(); + if ((name.startsWith("get") || name.startsWith("is")) + && ! "getClass".equals(name) + && Modifier.isPublic(method.getModifiers()) + && method.getParameterTypes().length == 0 + && (method.getReturnType() == String.class + || method.getReturnType() == Character.class + || method.getReturnType() == Boolean.class + || method.getReturnType() == Byte.class + || method.getReturnType() == Short.class + || method.getReturnType() == Integer.class + || method.getReturnType() == Long.class + || method.getReturnType() == Float.class + || method.getReturnType() == Double.class + || method.getReturnType() == Object.class)) { + Parameter parameter = method.getAnnotation(Parameter.class); + if (attribute){ + if (parameter == null || !parameter.attribute()) + continue; + } else { + if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { + continue; + } + } + String key; + if (parameter != null && parameter.key() != null && parameter.key().length() > 0) { + key = parameter.key(); + } else { + int i = name.startsWith("get") ? 3 : 2; + key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1); + } + Object value = method.invoke(config, new Object[0]); + if (attribute){ + if (prefix != null && prefix.length() > 0) { + key = prefix + "." + key; + } + if (value != null) parameters.put(key, value); + } else { + String str = String.valueOf(value).trim(); + if (value != null && str.length() > 0) { + if (prefix != null && prefix.length() > 0) { + key = prefix + "." + key; + } + if (parameter != null && parameter.escaped()) { + str = URLEncoder.encode(str, "UTF-8"); + } + parameters.put(key, str); + } else if (parameter != null && parameter.required()) { + throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null"); + } + } + } else if (!attribute && "getParameters".equals(name) + && Modifier.isPublic(method.getModifiers()) + && method.getParameterTypes().length == 0 + && method.getReturnType() == Map.class) { + Map map = (Map) method.invoke(config, new Object[0]); + if (map != null && map.size() > 0) { + if (prefix != null && prefix.length() > 0) { + for (Map.Entry entry : map.entrySet()) { + parameters.put(prefix + "." + entry.getKey(), entry.getValue()); + } + } else { + parameters.putAll(map); + } + } + } + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + + protected static void checkExtension(Class type, String property, String value) { + checkName(property, value); + if (value != null && value.length() > 0 + && ! ExtensionLoader.getExtensionLoader(type).hasExtension(value)) { + throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName()); + } + } + + protected static void checkMultiExtension(Class type, String property, String value) { + checkMultiName(property, value); + if (value != null && value.length() > 0) { + String[] values = value.split("\\s*[,]+\\s*"); + for (String v : values) { + if (v.startsWith(Constants.REMOVE_VALUE_PREFIX)) { + v = v.substring(1); + } + if (! ExtensionLoader.getExtensionLoader(type).hasExtension(v)) { + throw new IllegalStateException("No such extension " + v + " for " + property + "/" + type.getName()); + } + } + } + } + + protected static void checkLength(String property, String value) { + checkProperty(property, value, MAX_LENGTH, null); + } + + protected static void checkPathLength(String property, String value) { + checkProperty(property, value, MAX_PATH_LENGTH, null); + } + + protected static void checkName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_NAME); + } + + protected static void checkNameHasColon(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_COLON); + } + + protected static void checkMultiName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME); + } + + protected static void checkPathName(String property, String value) { + checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH); + } + + protected static void checkMethodName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME); + } + + protected static void checkParameterName(Map parameters) { + if (parameters == null || parameters.size() == 0) { + return; + } + for (Map.Entry entry : parameters.entrySet()) { + //change by tony.chenl parameter value maybe has colon.for example napoli address + checkNameHasColon(entry.getKey(), entry.getValue()); + } + } + + protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) { + if (value == null || value.length() == 0) { + return; + } + if(value.length() > maxlength){ + throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength); + } + if (pattern != null) { + Matcher matcher = pattern.matcher(value); + if(! matcher.matches()) { + throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contain illegal charactor, only digit, letter, '-', '_' and '.' is legal."); + } + } + } + + static { + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + if (logger.isInfoEnabled()) { + logger.info("Run shutdown hook now."); + } + ProtocolConfig.destroyAll(); + } + }, "DubboShutdownHook")); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractConsumerConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractConsumerConfig.java new file mode 100644 index 0000000000..a92e9bdb42 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractConsumerConfig.java @@ -0,0 +1,128 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.rpc.InvokerListener; +import com.alibaba.dubbo.rpc.RpcConstants; + + +/** + * AbstractConsumerConfig + * + * @see com.alibaba.dubbo.config.ReferenceConfig + * @author william.liangf + */ +public abstract class AbstractConsumerConfig extends AbstractReferenceConfig { + + private static final long serialVersionUID = -2786526984373031126L; + + // ======== 引用缺省值,当引用属性未设置时使用该缺省值替代 ======== + + // 检查服务提供者是否存在 + protected Boolean check; + + // 是否使用泛接口 + protected Boolean generic; + + // 优先从JVM内获取引用实例 + protected Boolean injvm; + + // lazy create connection + protected Boolean lazy; + + //stub是否支持event事件. //TODO slove merge problem + protected Boolean stubevent ;//= RpcConstants.DEFAULT_STUB_EVENT; + + public Boolean isCheck() { + return check; + } + + public void setCheck(Boolean check) { + this.check = check; + } + + @Parameter(excluded = true) + public Boolean isGeneric() { + return generic; + } + + public void setGeneric(Boolean generic) { + this.generic = generic; + } + + public Boolean isInjvm() { + return injvm; + } + + public void setInjvm(Boolean injvm) { + this.injvm = injvm; + } + + @Override + public void setTimeout(Integer timeout) { + super.setTimeout(timeout); + if (timeout != null && timeout > 0) { + System.setProperty("sun.rmi.transport.tcp.responseTimeout", String.valueOf(timeout)); + } + } + + @Parameter(key = Constants.REFERENCE_FILTER_KEY) + public String getFilter() { + return super.getFilter(); + } + + @Parameter(key = Constants.INVOKER_LISTENER_KEY) + public String getListener() { + return super.getListener(); + } + + @Override + public void setListener(String listener) { + checkMultiExtension(InvokerListener.class, "listener", listener); + super.setListener(listener); + } + + @Parameter(key = RpcConstants.LAZY_CONNECT_KEY) + public Boolean getLazy() { + return lazy; + } + + public void setLazy(Boolean lazy) { + this.lazy = lazy; + } + + @Override + public void setOnconnect(String onconnect) { + if (onconnect != null && onconnect.length() >0){ + this.stubevent = true; + } + super.setOnconnect(onconnect); + } + + @Override + public void setOndisconnect(String ondisconnect) { + if (ondisconnect != null && ondisconnect.length() >0){ + this.stubevent = true; + } + super.setOndisconnect(ondisconnect); + } + + @Parameter(key = RpcConstants.STUB_EVENT_KEY) + public Boolean getStubevent() { + return stubevent; + } +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractMethodConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractMethodConfig.java new file mode 100644 index 0000000000..a44d85bb33 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractMethodConfig.java @@ -0,0 +1,109 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.util.Map; + +import com.alibaba.dubbo.rpc.cluster.LoadBalance; + +/** + * AbstractMethodConfig + * + * @author william.liangf + */ +public abstract class AbstractMethodConfig extends AbstractConfig { + + private static final long serialVersionUID = 1L; + + // 远程调用超时时间(毫秒) + protected Integer timeout; + + // 重试次数 + protected Integer retries; + + // 最大并发调用 + protected Integer actives; + + // 负载均衡 + protected String loadbalance; + + // 是否异步 + protected Boolean async; + + // 异步发送是否等待发送成功 + protected Boolean sent; + + // 自定义参数 + protected Map parameters; + + public Integer getTimeout() { + return timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public Integer getRetries() { + return retries; + } + + public void setRetries(Integer retries) { + this.retries = retries; + } + + public String getLoadbalance() { + return loadbalance; + } + + public void setLoadbalance(String loadbalance) { + checkExtension(LoadBalance.class, "loadbalance", loadbalance); + this.loadbalance = loadbalance; + } + + public Boolean isAsync() { + return async; + } + + public void setAsync(Boolean async) { + this.async = async; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + checkParameterName(parameters); + this.parameters = parameters; + } + + public Integer getActives() { + return actives; + } + + public void setActives(Integer actives) { + this.actives = actives; + } + + public Boolean getSent() { + return sent; + } + + public void setSent(Boolean sent) { + this.sent = sent; + } +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractReferenceConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractReferenceConfig.java new file mode 100644 index 0000000000..ae5a63ba2d --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractReferenceConfig.java @@ -0,0 +1,342 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubbo.registry.support.UrlUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.InvokerListener; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +/** + * AbstractDefaultConfig + * + * @author william.liangf + */ +public abstract class AbstractReferenceConfig extends AbstractMethodConfig { + + private static final long serialVersionUID = -1559314110797223229L; + + // 服务接口的本地实现类名 + protected String local; + + // 服务接口的本地实现类名 + protected String stub; + + // 服务接口的失败mock实现类名 + protected String mock; + + // 服务监控 + protected String monitor; + + // 代理类型 + protected String proxy; + + // 集群方式 + protected String cluster; + + // 过滤器 + protected String filter; + + // 监听器 + protected String listener; + + // 负责人 + protected String owner; + + // 连接数限制 + protected Integer connections; + + // 连接数限制 + protected String layer; + + // 应用信息 + protected ApplicationConfig application; + + // 注册中心 + protected List registries; + + // callback实例个数限制 + private Integer callbacks; + + // 连接事件 + protected String onconnect; + + // 断开事件 + protected String ondisconnect; + + protected void checkRegistry() { + // 兼容旧版本 + if (registries == null || registries.size() == 0) { + String address = getLegacyProperty("dubbo.registry.address"); + if (address != null && address.length() > 0) { + registries = new ArrayList(); + String[] as = address.split("\\s*[|]+\\s*"); + for (String a : as) { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress(a); + registries.add(registryConfig); + } + } + } + if (registries == null || registries.size() == 0) { + throw new IllegalStateException((getClass().getSimpleName().startsWith("Reference") + ? "No such any registry to refer service in consumer " + : "No such any registry to export service in provider ") + + NetUtils.getLocalHost() + + " use dubbo version " + + Version.getVersion() + + ", Please add to your spring config. If you want unregister, please set "); + } + } + + @SuppressWarnings("deprecation") + protected void checkApplication() { + // 兼容旧版本 + if (application == null) { + String app = getLegacyProperty("dubbo.application.name"); + if (app != null && app.length() > 0) { + application = new ApplicationConfig(); + application.setName(app); + } + } + if (application == null) { + throw new IllegalStateException( + "No such application config! Please add to your spring config."); + } + + + String wait = getLegacyProperty(RpcConstants.SHUTDOWN_TIMEOUT_KEY); + if (wait != null && wait.trim().length() > 0) { + System.setProperty(RpcConstants.SHUTDOWN_TIMEOUT_KEY, wait.trim()); + } else { + wait = getLegacyProperty(RpcConstants.SHUTDOWN_TIMEOUT_SECONDS_KEY); + if (wait != null && wait.trim().length() > 0) { + System.setProperty(RpcConstants.SHUTDOWN_TIMEOUT_SECONDS_KEY, wait.trim()); + } + } + } + + protected List loadRegistries() { + checkRegistry(); + List registryList = new ArrayList(); + if (registries != null && registries.size() > 0) { + for (RegistryConfig config : registries) { + if (! RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(config.getAddress())) { + if (config.getAddress() == null || config.getAddress().length() == 0) { + throw new IllegalStateException("registry address == null"); + } + Map map = new HashMap(); + appendParameters(map, config); + map.put("path", RegistryService.class.getName()); + List urls = UrlUtils.parseURLs(config.getAddress(), map); + for (URL url : urls) { + url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol()); + url = url.setProtocol(Constants.REGISTRY_PROTOCOL); + registryList.add(url); + } + } + } + } + return registryList; + } + + /** + * @deprecated Replace to getStub() + * @return + */ + @Deprecated + public String getLocal() { + return local; + } + + /** + * @deprecated Replace to setStub(String) + * @param local + */ + @Deprecated + public void setLocal(String local) { + checkName("local", local); + this.local = local; + } + + public String getStub() { + return stub; + } + + public void setStub(String stub) { + checkName("stub", stub); + this.stub = stub; + } + + public void setLocal(Boolean local) { + if (local == null) { + setLocal((String) null); + } else { + setLocal(String.valueOf(local)); + } + } + + public String getMock() { + return mock; + } + + public void setMock(String mock) { + checkName("mock", mock); + this.mock = mock; + } + + public void setMock(Boolean mock) { + if (mock == null) { + setMock((String) null); + } else { + setMock(String.valueOf(mock)); + } + } + + public String getCluster() { + return cluster; + } + + public void setCluster(String cluster) { + checkExtension(Cluster.class, "cluster", cluster); + this.cluster = cluster; + } + + public String getProxy() { + return proxy; + } + + public void setProxy(String proxy) { + checkExtension(ProxyFactory.class, "proxy", proxy); + this.proxy = proxy; + } + + public Integer getConnections() { + return connections; + } + + public void setConnections(Integer connections) { + this.connections = connections; + } + + @Parameter(key = Constants.REFERENCE_FILTER_KEY) + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + checkMultiExtension(Filter.class, "filter", filter); + this.filter = filter; + } + + @Parameter(key = Constants.INVOKER_LISTENER_KEY) + public String getListener() { + checkMultiExtension(InvokerListener.class, "listener", listener); + return listener; + } + + public void setListener(String listener) { + this.listener = listener; + } + + public String getLayer() { + return layer; + } + + public void setLayer(String layer) { + checkNameHasColon("layer", layer); + this.layer = layer; + } + + public ApplicationConfig getApplication() { + return application; + } + + public void setApplication(ApplicationConfig application) { + this.application = application; + } + + public RegistryConfig getRegistry() { + return registries == null || registries.size() == 0 ? null : registries.get(0); + } + + public void setRegistry(RegistryConfig registry) { + List registries = new ArrayList(1); + registries.add(registry); + this.registries = registries; + } + + public List getRegistries() { + return registries; + } + + @SuppressWarnings({ "unchecked" }) + public void setRegistries(List registries) { + this.registries = (List)registries; + } + + public String getMonitor() { + return monitor; + } + + public void setMonitor(String monitor) { + this.monitor = monitor; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public void setCallbacks(Integer callbacks) { + this.callbacks = callbacks; + } + + public Integer getCallbacks() { + return callbacks; + } + + public String getOnconnect() { + return onconnect; + } + + public void setOnconnect(String onconnect) { + this.onconnect = onconnect; + } + + public String getOndisconnect() { + return ondisconnect; + } + + public void setOndisconnect(String ondisconnect) { + this.ondisconnect = ondisconnect; + } +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java new file mode 100644 index 0000000000..3700667b64 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/AbstractServiceConfig.java @@ -0,0 +1,197 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.util.Arrays; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.rpc.ExporterListener; + +/** + * AbstractServiceConfig + * + * @author william.liangf + */ +public abstract class AbstractServiceConfig extends AbstractReferenceConfig { + + private static final long serialVersionUID = 1L; + + // 服务版本 + protected String version; + + // 服务分组 + protected String group; + + // 服务是否已经deprecated + protected Boolean deprecated; + + // 延迟注册 + protected Integer delay; + + // 权重 + protected Integer weight; + + // 应用文档 + protected String document; + + // 在注册中心上注册成动态的还是静态的服务 + protected Boolean dynamic; + + // 是否使用令牌 + protected String token; + + // 访问日志 + protected String accesslog; + + // 允许执行请求数 + private Integer executes; + + protected List protocols; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + checkName("version", version); + this.version = version; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + checkName("group", group); + this.group = group; + } + + public Integer getDelay() { + return delay; + } + + public void setDelay(Integer delay) { + this.delay = delay; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + @Parameter(escaped = true) + public String getDocument() { + return document; + } + + public void setDocument(String document) { + this.document = document; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + checkName("token", token); + this.token = token; + } + + public void setToken(Boolean token) { + if (token == null) { + setToken((String) null); + } else { + setToken(String.valueOf(token)); + } + } + + public Boolean isDeprecated() { + return deprecated; + } + + public void setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + } + + public Boolean isDynamic() { + return dynamic; + } + + public void setDynamic(Boolean dynamic) { + this.dynamic = dynamic; + } + + public List getProtocols() { + return protocols; + } + + @SuppressWarnings({ "unchecked" }) + public void setProtocols(List protocols) { + this.protocols = (List)protocols; + } + + public ProtocolConfig getProtocol() { + return protocols == null || protocols.size() == 0 ? null : protocols.get(0); + } + + public void setProtocol(ProtocolConfig protocol) { + this.protocols = Arrays.asList(new ProtocolConfig[] {protocol}); + } + + public String getAccesslog() { + return accesslog; + } + + public void setAccesslog(String accesslog) { + this.accesslog = accesslog; + } + + public void setAccesslog(Boolean accesslog) { + if (accesslog == null) { + setAccesslog((String) null); + } else { + setAccesslog(String.valueOf(accesslog)); + } + } + + public Integer getExecutes() { + return executes; + } + + public void setExecutes(Integer executes) { + this.executes = executes; + } + + @Parameter(key = Constants.SERVICE_FILTER_KEY) + public String getFilter() { + return super.getFilter(); + } + + @Parameter(key = Constants.EXPORTER_LISTENER_KEY) + public String getListener() { + return super.getListener(); + } + + @Override + public void setListener(String listener) { + checkMultiExtension(ExporterListener.class, "listener", listener); + super.setListener(listener); + } +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java new file mode 100644 index 0000000000..2107c7b598 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java @@ -0,0 +1,146 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import com.alibaba.dubbo.common.Constants; + + +/** + * ApplicationConfig + * + * @author william.liangf + */ +public class ApplicationConfig extends AbstractConfig { + + private static final long serialVersionUID = 5508512956753757169L; + + // 应用名称 + private String name; + + // 应用负责人 + private String owner; + + // 组织名(BU或部门) + private String organization; + + // 分层 + private String architecture; + + // 环境,如:dev/test/run + private String environment; + + // 服务监控 + protected String monitor; + + public ApplicationConfig() { + } + + public ApplicationConfig(String name) { + setName(name); + } + + @Parameter(key = Constants.APPLICATION_KEY, required = true) + public String getName() { + return name; + } + + public void setName(String name) { + checkName("name", name); + this.name = name; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + checkName("owner", owner); + this.owner = owner; + } + + public String getOrganization() { + return organization; + } + + public void setOrganization(String organization) { + checkName("organization", organization); + this.organization = organization; + } + + public String getArchitecture() { + return architecture; + } + + public void setArchitecture(String architecture) { + checkName("architecture", architecture); + this.architecture = architecture; + } + + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + checkName("environment", environment); + if(environment != null) { + if (! ("develop".equals(environment) || "test".equals(environment) || "product".equals(environment))) { + throw new IllegalStateException("Unsupported environment: " + environment + ", only support develop/test/product, default is product."); + } + } + this.environment = environment; + } + + public String getMonitor() { + return monitor; + } + + public void setMonitor(String monitor) { + this.monitor = monitor; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(" 0) { + buf.append(" name=\""); + buf.append(name); + buf.append("\""); + } + if (owner != null && owner.length() > 0) { + buf.append(" owner=\""); + buf.append(owner); + buf.append("\""); + } + if (organization != null && organization.length() > 0) { + buf.append(" organization=\""); + buf.append(organization); + buf.append("\""); + } + if (architecture != null && architecture.length() > 0) { + buf.append(" architecture=\""); + buf.append(architecture); + buf.append("\""); + } + if (environment != null && environment.length() > 0) { + buf.append(" environment=\""); + buf.append(environment); + buf.append("\""); + } + buf.append(" />"); + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ArgumentConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ArgumentConfig.java new file mode 100644 index 0000000000..c99ddd3897 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ArgumentConfig.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.io.Serializable; + +/** + * @author chao.liuc + */ +public class ArgumentConfig implements Serializable { + + private static final long serialVersionUID = -2165482463925213595L; + + //arugment index -1 represents not set + private Integer index = -1; + + //argument type + private String type; + + //callback interface + private Boolean callback; + + public void setIndex(Integer index) { + this.index = index; + } + @Parameter(excluded = true) + public Integer getIndex() { + return index; + } + @Parameter(excluded = true) + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public void setCallback(Boolean callback) { + this.callback = callback; + } + + public Boolean isCallback() { + return callback; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java new file mode 100644 index 0000000000..400648472f --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +/** + * ConsumerConfig + * + * @author william.liangf + */ +public class ConsumerConfig extends AbstractConsumerConfig { + + private static final long serialVersionUID = 2827274711143680600L; + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/MethodConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/MethodConfig.java new file mode 100644 index 0000000000..8ed0a60ba2 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/MethodConfig.java @@ -0,0 +1,208 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.util.List; + +import com.alibaba.dubbo.rpc.RpcConstants; + +/** + * MethodConfig + * + * @author william.liangf + */ +public class MethodConfig extends AbstractMethodConfig { + + private static final long serialVersionUID = 884908855422675941L; + + // 方法名 + private String name; + + // 统计参数 + private Integer stat; + + // 是否重试 + private Boolean retry; + + // 是否为可靠异步 + private Boolean reliable; + + // 方法使用线程数限制 + private Integer executes; + + // 是否过时 + private Boolean deprecated; + + // 是否需要返回 + private Boolean sticky; + + // 是否需要返回 + private Boolean isReturn; + + //异步调用回调实例 + private Object oninvoke; + + //异步调用回调方法 + private String oninvokeMethod; + + //异步调用回调实例 + private Object onreturn; + + //异步调用回调方法 + private String onreturnMethod; + + //异步调用异常回调实例 + private Object onthrow; + + //异步调用异常回调方法 + private String onthrowMethod; + + private List arguments; + + @Parameter(excluded = true) + public String getName() { + return name; + } + + public void setName(String name) { + checkMethodName("name", name); + this.name = name; + } + + public Integer getStat() { + return stat; + } + + @Deprecated + public void setStat(Integer stat) { + this.stat = stat; + } + + @Deprecated + public Boolean isRetry() { + return retry; + } + + @Deprecated + public void setRetry(Boolean retry) { + this.retry = retry; + } + + @Deprecated + public Boolean isReliable() { + return reliable; + } + + @Deprecated + public void setReliable(Boolean reliable) { + this.reliable = reliable; + } + + public Integer getExecutes() { + return executes; + } + + public void setExecutes(Integer executes) { + this.executes = executes; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public void setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + } + + @SuppressWarnings("unchecked") + public void setArguments(List arguments) { + this.arguments = (List) arguments; + } + + public List getArguments() { + return arguments; + } + + public Boolean getSticky() { + return sticky; + } + + public void setSticky(Boolean sticky) { + this.sticky = sticky; + } + + @Parameter(key = RpcConstants.ON_RETURN_INSTANCE_KEY, excluded = true, attribute = true) + public Object getOnreturn() { + return onreturn; + } + + public void setOnreturn(Object onreturn) { + this.onreturn = onreturn; + } + + @Parameter(key = RpcConstants.ON_RETURN_METHOD_KEY, excluded = true, attribute = true) + public String getOnreturnMethod() { + return onreturnMethod; + } + + public void setOnreturnMethod(String onreturnMethod) { + this.onreturnMethod = onreturnMethod; + } + + @Parameter(key = RpcConstants.ON_THROW_INSTANCE_KEY, excluded = true, attribute = true) + public Object getOnthrow() { + return onthrow; + } + + public void setOnthrow(Object onthrow) { + this.onthrow = onthrow; + } + + @Parameter(key = RpcConstants.ON_THROW_METHOD_KEY, excluded = true, attribute = true) + public String getOnthrowMethod() { + return onthrowMethod; + } + + public void setOnthrowMethod(String onthrowMethod) { + this.onthrowMethod = onthrowMethod; + } + + @Parameter(key = RpcConstants.ON_INVOKE_INSTANCE_KEY, excluded = true, attribute = true) + public Object getOninvoke() { + return oninvoke; + } + + public void setOninvoke(Object oninvoke) { + this.oninvoke = oninvoke; + } + + @Parameter(key = RpcConstants.ON_INVOKE_METHOD_KEY, excluded = true, attribute = true) + public String getOninvokeMethod() { + return oninvokeMethod; + } + + public void setOninvokeMethod(String oninvokeMethod) { + this.oninvokeMethod = oninvokeMethod; + } + + public Boolean isReturn() { + return isReturn; + } + + public void setReturn(Boolean isReturn) { + this.isReturn = isReturn; + } +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/MonitorConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/MonitorConfig.java new file mode 100644 index 0000000000..c9eeb7a4fb --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/MonitorConfig.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.io.Serializable; + +/** + * MonitorConfig + * + * @author william.liangf + */ +public class MonitorConfig implements Serializable { + + private static final long serialVersionUID = -1184681514659198203L; + + private String address; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/Parameter.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/Parameter.java new file mode 100644 index 0000000000..066756cae8 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/Parameter.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Parameter + * + * @author william.liangf + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Parameter { + + String key() default ""; + + boolean required() default false; + + boolean excluded() default false; + + boolean escaped() default false; + + boolean attribute() default false; + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java new file mode 100644 index 0000000000..7c4d2a9f23 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java @@ -0,0 +1,337 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.util.Map; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.common.threadpool.ThreadPool; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.Transporter; +import com.alibaba.dubbo.remoting.exchange.Exchanger; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.rpc.Protocol; + +/** + * ProtocolConfig + * + * @author william.liangf + */ +public class ProtocolConfig extends AbstractConfig { + + private static final long serialVersionUID = 6913423882496634749L; + + // 服务协议 + private String name; + + // 服务IP地址(多网卡时使用) + private String host; + + // 服务端口 + private Integer port; + + // 上下文路径 + private String contextpath; + + // 线程池类型 + private String threadpool; + + // 线程池大小(固定大小) + private Integer threads; + + // IO线程池大小(固定大小) + private Integer iothreads; + + // 线程池队列大小 + private Integer queues; + + // 最大接收连接数 + private Integer accepts; + + // 协议编码 + private String codec; + + // 序列化方式 + private String serialization; + + // 字符集 + private String charset; + + // 最大请求数据长度 + private Integer payload; + + // 缓存区大小 + private Integer buffer; + + // 访问日志 + private String accesslog; + + // 网络传输方式 + private String transporter; + + // 信息交换方式 + private String exchanger; + + // 服务器端实现 + private String server; + + // 客户端实现 + private String client; + + // 支持的telnet命令,多个命令用逗号分隔 + private String telnet; + + // status检查 + private String status; + + // 参数 + private Map parameters; + + public ProtocolConfig() { + } + + public ProtocolConfig(String name) { + setName(name); + } + + @Parameter(excluded = true) + public String getName() { + return name; + } + + public void setName(String name) { + checkName("name", name); + this.name = name; + } + + @Parameter(excluded = true) + public String getHost() { + return host; + } + + public void setHost(String host) { + checkName("host", host); + this.host = host; + } + + @Parameter(excluded = true) + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + @Deprecated + @Parameter(excluded = true) + public String getPath() { + return getContextpath(); + } + + @Deprecated + public void setPath(String path) { + setContextpath(path); + } + + @Parameter(excluded = true) + public String getContextpath() { + return contextpath; + } + + public void setContextpath(String contextpath) { + checkPathName("contextpath", contextpath); + this.contextpath = contextpath; + } + + public String getThreadpool() { + return threadpool; + } + + public void setThreadpool(String threadpool) { + checkExtension(ThreadPool.class, "threadpool", threadpool); + this.threadpool = threadpool; + } + + public Integer getThreads() { + return threads; + } + + public void setThreads(Integer threads) { + this.threads = threads; + } + + public Integer getIothreads() { + return iothreads; + } + + public void setIothreads(Integer iothreads) { + this.iothreads = iothreads; + } + + public Integer getQueues() { + return queues; + } + + public void setQueues(Integer queues) { + this.queues = queues; + } + + public Integer getAccepts() { + return accepts; + } + + public void setAccepts(Integer accepts) { + this.accepts = accepts; + } + + public String getCodec() { + return codec; + } + + public void setCodec(String codec) { + if ("dubbo".equals(name)) { + checkMultiExtension(Codec.class, "codec", codec); + } + this.codec = codec; + } + + public String getSerialization() { + return serialization; + } + + public void setSerialization(String serialization) { + if ("dubbo".equals(name)) { + checkMultiExtension(Serialization.class, "serialization", serialization); + } + this.serialization = serialization; + } + + public String getCharset() { + return charset; + } + + public void setCharset(String charset) { + this.charset = charset; + } + + public Integer getPayload() { + return payload; + } + + public void setPayload(Integer payload) { + this.payload = payload; + } + + public Integer getBuffer() { + return buffer; + } + + public void setBuffer(Integer buffer) { + this.buffer = buffer; + } + + public String getServer() { + return server; + } + + public void setServer(String server) { + if ("dubbo".equals(name)) { + checkMultiExtension(Transporter.class, "server", server); + } + this.server = server; + } + + public String getClient() { + return client; + } + + public void setClient(String client) { + if ("dubbo".equals(name)) { + checkMultiExtension(Transporter.class, "client", client); + } + this.client = client; + } + + public String getAccesslog() { + return accesslog; + } + + public void setAccesslog(String accesslog) { + this.accesslog = accesslog; + } + + public String getTelnet() { + return telnet; + } + + public void setTelnet(String telnet) { + checkMultiExtension(TelnetHandler.class, "telnet", telnet); + this.telnet = telnet; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + checkMultiExtension(StatusChecker.class, "status", status); + this.status = status; + } + + public String getTransporter() { + return transporter; + } + + public void setTransporter(String transporter) { + checkExtension(Transporter.class, "transporter", transporter); + this.transporter = transporter; + } + + public String getExchanger() { + return exchanger; + } + + public void setExchanger(String exchanger) { + checkExtension(Exchanger.class, "exchanger", exchanger); + this.exchanger = exchanger; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + public void destory() { + if (name != null) { + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).destroy();; + } + } + + public static void destroyAll() { + AbstractRegistryFactory.destroyAll(); + for (String protocol : ExtensionLoader.getExtensionLoader(Protocol.class).getSupportedExtensions()) { + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(protocol).destroy(); + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ProviderConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ProviderConfig.java new file mode 100644 index 0000000000..7830e77676 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ProviderConfig.java @@ -0,0 +1,340 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.util.Arrays; + +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.common.threadpool.ThreadPool; +import com.alibaba.dubbo.remoting.Transporter; +import com.alibaba.dubbo.remoting.exchange.Exchanger; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; + +/** + * ProviderConfig + * + * @see com.alibaba.dubbo.config.ProtocolConfig + * @see com.alibaba.dubbo.config.ServiceConfig + * @author william.liangf + */ +public class ProviderConfig extends AbstractServiceConfig { + + private static final long serialVersionUID = 6913423882496634749L; + + // ======== 协议缺省值,当协议属性未设置时使用该缺省值替代 ======== + + // 服务IP地址(多网卡时使用) + private String host; + + // 服务端口 + private Integer port; + + // 上下 + private String contextpath; + + // 线程池类型 + private String threadpool; + + // 线程池大小(固定大小) + private Integer threads; + + // IO线程池大小(固定大小) + private Integer iothreads; + + // 线程池队列大小 + private Integer queues; + + // 最大接收连接数 + private Integer accepts; + + // 协议编码 + private String codec; + + // 序列化方式 + private String serialization; + + // 字符集 + private String charset; + + // 最大请求数据长度 + private Integer payload; + + // 缓存区大小 + private Integer buffer; + + // 网络传输方式 + private String transporter; + + // 信息交换方式 + private String exchanger; + + // 服务器端实现 + private String server; + + // 客户端实现 + private String client; + + // 支持的telnet命令,多个命令用逗号分隔 + private String telnet; + + // status检查 + private String status; + + // 停止时等候时间 + private Integer wait; + + // 是否为缺省 + private Boolean isDefault; + + @Deprecated + public void setProtocol(String protocol) { + this.protocols = Arrays.asList(new ProtocolConfig[] {new ProtocolConfig(protocol)}); + } + + @Parameter(excluded = true) + public Boolean isDefault() { + return isDefault; + } + + @Deprecated + public void setDefault(Boolean isDefault) { + this.isDefault = isDefault; + } + + @Parameter(excluded = true) + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + @Parameter(excluded = true) + public Integer getPort() { + return port; + } + + @Deprecated + public void setPort(Integer port) { + this.port = port; + } + + @Deprecated + @Parameter(excluded = true) + public String getPath() { + return getContextpath(); + } + + @Deprecated + public void setPath(String path) { + setContextpath(path); + } + + @Parameter(excluded = true) + public String getContextpath() { + return contextpath; + } + + public void setContextpath(String contextpath) { + checkPathName("contextpath", contextpath); + this.contextpath = contextpath; + } + + public String getThreadpool() { + return threadpool; + } + + public void setThreadpool(String threadpool) { + checkExtension(ThreadPool.class, "threadpool", threadpool); + this.threadpool = threadpool; + } + + public Integer getThreads() { + return threads; + } + + public void setThreads(Integer threads) { + this.threads = threads; + } + + public Integer getIothreads() { + return iothreads; + } + + public void setIothreads(Integer iothreads) { + this.iothreads = iothreads; + } + + public Integer getQueues() { + return queues; + } + + public void setQueues(Integer queues) { + this.queues = queues; + } + + public Integer getAccepts() { + return accepts; + } + + public void setAccepts(Integer accepts) { + this.accepts = accepts; + } + + public String getCodec() { + return codec; + } + + public void setCodec(String codec) { + this.codec = codec; + } + + public String getSerialization() { + return serialization; + } + + public void setSerialization(String serialization) { + this.serialization = serialization; + } + + public String getCharset() { + return charset; + } + + public void setCharset(String charset) { + this.charset = charset; + } + + public Integer getPayload() { + return payload; + } + + public void setPayload(Integer payload) { + this.payload = payload; + } + + public Integer getBuffer() { + return buffer; + } + + public void setBuffer(Integer buffer) { + this.buffer = buffer; + } + + public String getServer() { + return server; + } + + public void setServer(String server) { + this.server = server; + } + + public String getClient() { + return client; + } + + public void setClient(String client) { + this.client = client; + } + + public String getTelnet() { + return telnet; + } + + public void setTelnet(String telnet) { + checkMultiExtension(TelnetHandler.class, "telnet", telnet); + this.telnet = telnet; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + checkMultiExtension(StatusChecker.class, "status", status); + this.status = status; + } + + @Parameter(key = "default.cluster") + @Override + public String getCluster() { + return super.getCluster(); + } + + @Parameter(key = "default.connections") + @Override + public Integer getConnections() { + return super.getConnections(); + } + + @Parameter(key = "default.timeout") + @Override + public Integer getTimeout() { + return super.getTimeout(); + } + + @Parameter(key = "default.retries") + @Override + public Integer getRetries() { + return super.getRetries(); + } + + @Parameter(key = "default.loadbalance") + @Override + public String getLoadbalance() { + return super.getLoadbalance(); + } + + @Parameter(key = "default.async") + @Override + public Boolean isAsync() { + return super.isAsync(); + } + + @Parameter(key = "default.actives") + @Override + public Integer getActives() { + return super.getActives(); + } + + public String getTransporter() { + return transporter; + } + + public void setTransporter(String transporter) { + checkExtension(Transporter.class, "transporter", transporter); + this.transporter = transporter; + } + + public String getExchanger() { + return exchanger; + } + + public void setExchanger(String exchanger) { + checkExtension(Exchanger.class, "exchanger", exchanger); + this.exchanger = exchanger; + } + + public Integer getWait() { + return wait; + } + + public void setWait(Integer wait) { + this.wait = wait; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java new file mode 100644 index 0000000000..fbb11d2dce --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java @@ -0,0 +1,495 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.StaticContext; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory; +import com.alibaba.dubbo.rpc.cluster.support.AvailableCluster; +import com.alibaba.dubbo.rpc.cluster.support.ClusterUtils; +import com.alibaba.dubbo.rpc.injvm.InjvmProtocol; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * ReferenceConfig + * + * @author william.liangf + */ +public class ReferenceConfig extends AbstractConsumerConfig { + + private static final long serialVersionUID = -5864351140409987595L; + + private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension(); + + private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + // 接口类型 + private String interfaceName; + + private Class interfaceClass; + + // 版本 + private String version; + + // 服务分组 + private String group; + + // 客户端类型 + private String client; + + // 点对点直连服务提供地址 + private String url; + + // 方法配置 + private List methods; + + // 缺省配置 + private ConsumerConfig consumer; + + // 接口代理类引用 + private transient T ref; + + private transient Invoker invoker; + + private transient boolean initialized; + + private transient boolean destroyed; + + public synchronized T get() { + if (destroyed){ + throw new IllegalStateException("Already destroyed!"); + } + if (ref == null) { + init(); + } + return ref; + } + + public synchronized void destroy() { + if (destroyed){ + throw new IllegalStateException("Already destroyed!"); + } + destroyed = true; + try { + invoker.destroy(); + } catch (Throwable t) { + logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ").", t); + } + invoker = null; + ref = null; + } + + private void init() { + if (initialized) { + return; + } + initialized = true; + if (interfaceName == null || interfaceName.length() == 0) { + throw new IllegalStateException(" interface not allow null!"); + } + // 获取消费者全局配置 + checkDefault(); + if (generic == null && consumer != null) { + generic = consumer.isGeneric(); + } + if (generic == null) { + generic = false; + } + if (generic) { + interfaceClass = GenericService.class; + } else { + try { + interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() + .getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + checkInterface(); + } + String resolve = System.getProperty(interfaceName); + String resolveFile = null; + if (resolve == null || resolve.length() == 0) { + resolveFile = System.getProperty("dubbo.resolve.file"); + if (resolveFile == null || resolveFile.length() == 0) { + File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties"); + if (userResolveFile.exists()) { + resolveFile = userResolveFile.getAbsolutePath(); + } + } + if (resolveFile != null && resolveFile.length() > 0) { + Properties properties = new Properties(); + FileInputStream fis = null; + try { + fis = new FileInputStream(new File(resolveFile)); + properties.load(fis); + } catch (IOException e) { + throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e); + } finally { + try { + if(null != fis) fis.close(); + } catch (IOException e) { + logger.warn(e.getMessage(), e); + } + } + resolve = properties.getProperty(interfaceName); + } + } + if (resolve != null && resolve.length() > 0) { + url = resolve; + if (logger.isWarnEnabled()) { + if (resolveFile != null && resolveFile.length() > 0) { + logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service."); + } else { + logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service."); + } + } + } + if (consumer != null) { + if (application == null) { + application = consumer.getApplication(); + } + if (registries == null) { + registries = consumer.getRegistries(); + } + } + checkApplication(); + Map map = new HashMap(); + Map attributes = new HashMap(); + map.put("dubbo", Version.getVersion()); + if (! generic) { + map.put("revision", Version.getVersion(interfaceClass, version)); + map.put("methods", StringUtils.join(new HashSet(Arrays.asList(Wrapper.getWrapper(interfaceClass).getDeclaredMethodNames())), ",")); + } + map.put(Constants.INTERFACE_KEY, interfaceName); + appendParameters(map, application); + appendParameters(map, consumer, Constants.DEFAULT_KEY); + appendParameters(map, this); + String prifix = StringUtils.getServiceKey(map); + if (methods != null && methods.size() > 0) { + for (MethodConfig method : methods) { + appendParameters(map, method, method.getName()); + appendAttributes(attributes, method, prifix +"."+method.getName()); + checkAndConvertImplicitConfig(method, map, attributes); + } + } + //attributes通过系统context进行存储. + StaticContext.getSystemContext().putAll(attributes); + ref = createProxy(map); + } + + private static void checkAndConvertImplicitConfig(MethodConfig method, Map map, Map attributes){ + //check config conflict + if (Boolean.FALSE.equals(method.isReturn()) && (method.getOnreturn() != null || method.getOnthrow() != null)) { + throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been setted."); + } + //convert onreturn methodName to Method + String onReturnMethodKey = StaticContext.getKey(map,method.getName(),RpcConstants.ON_RETURN_METHOD_KEY); + Object onReturnMethod = attributes.get(onReturnMethodKey); + if (onReturnMethod != null && onReturnMethod instanceof String){ + attributes.put(onReturnMethodKey, getMethodByName(method.getOnreturn().getClass(), onReturnMethod.toString())); + } + //convert onthrow methodName to Method + String onThrowMethodKey = StaticContext.getKey(map,method.getName(),RpcConstants.ON_THROW_METHOD_KEY); + Object onThrowMethod = attributes.get(onThrowMethodKey); + if (onThrowMethod != null && onThrowMethod instanceof String){ + attributes.put(onThrowMethodKey, getMethodByName(method.getOnthrow().getClass(), onThrowMethod.toString())); + } + //convert oninvoke methodName to Method + String onInvokeMethodKey = StaticContext.getKey(map,method.getName(),RpcConstants.ON_INVOKE_METHOD_KEY); + Object onInvokeMethod = attributes.get(onInvokeMethodKey); + if (onInvokeMethod != null && onInvokeMethod instanceof String){ + attributes.put(onInvokeMethodKey, getMethodByName(method.getOninvoke().getClass(), onInvokeMethod.toString())); + } + } + + private static Method getMethodByName(Class clazz, String methodName){ + try { + return ReflectUtils.findMethodByMethodName(clazz, methodName); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private T createProxy(Map map) { + Boolean j = injvm; + if (j == null && consumer != null) { + j = consumer.isInjvm(); + } + if (j != null && j) { + URL url = new URL(InjvmProtocol.NAME, NetUtils.LOCALHOST, InjvmProtocol.DEFAULT_PORT, interfaceClass.getName()).addParameters(map); + invoker = protocol.refer(interfaceClass, url); + if (logger.isInfoEnabled()) { + logger.info("Using injvm service " + interfaceClass.getName()); + } + } else { + List urls = new ArrayList(); + if (url != null && url.length() > 0) { // 用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL + String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url); + if (us != null && us.length > 0) { + for (String u : us) { + URL url = URL.valueOf(u); + if (url.getPath() == null || url.getPath().length() == 0) { + url = url.setPath(interfaceName); + } + if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { + urls.add(url.addParameterAndEncoded(RpcConstants.REFER_KEY, StringUtils.toQueryString(map))); + } else { + urls.add(ClusterUtils.mergeUrl(url, map)); + } + } + } + } else { // 通过注册中心配置拼装URL + List us = loadRegistries(); + if (us != null && us.size() > 0) { + for (URL u : us) { + String monitor = convertMonitor(map.get(Constants.MONITOR_KEY), u); + if (monitor != null && monitor.length() > 0) { + map.put(Constants.MONITOR_KEY, monitor); + } + urls.add(u.addParameterAndEncoded(RpcConstants.REFER_KEY, StringUtils.toQueryString(map))); + } + } + if (urls == null || urls.size() == 0) { + throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config to your spring config."); + } + } + if (urls.size() == 1) { + invoker = protocol.refer(interfaceClass, urls.get(0)); + } else { + List> invokers = new ArrayList>(); + URL registryURL = null; + for (URL url : urls) { + invokers.add(protocol.refer(interfaceClass, url)); + if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { + registryURL = url; // 用了最后一个registry url + } + } + if (registryURL != null) { // 有 注册中心协议的URL + // 对有注册中心的Cluster 只用 AvailableCluster + URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); + invoker = cluster.merge(new StaticDirectory(u, invokers)); + } else { // 不是 注册中心的URL + invoker = cluster.merge(new StaticDirectory(invokers)); + } + } + } + Boolean c = check; + if (c == null && consumer != null) { + c = consumer.isCheck(); + } + if (c == null) { + c = true; // default true + } + if (c && ! invoker.isAvailable()) { + throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); + } + if (logger.isInfoEnabled()) { + logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); + } + // 创建服务代理 + return (T) proxyFactory.getProxy(invoker); + } + + private void checkInterface() { + // 检查接口类型必需为接口 + if(! interfaceClass.isInterface()) { + throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); + } + // 检查方法是否在接口中存在 + if (methods != null && methods.size() > 0) { + for (MethodConfig methodBean : methods) { + String methodName = methodBean.getName(); + if (methodName == null || methodName.length() == 0) { + throw new IllegalStateException(" name attribute is required! Please check: "); + } + boolean hasMethod = false; + for (Method method : interfaceClass.getMethods()) { + if (method.getName().equals(methodName)) { + hasMethod = true; + break; + } + } + if (! hasMethod) { + throw new IllegalStateException("The interface " + interfaceClass.getName() + + " not found method " + methodName); + } + } + } + if (ConfigUtils.isNotEmpty(local)) { + Class localClass = ConfigUtils.isDefault(local) ? ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local); + if (! interfaceClass.isAssignableFrom(localClass)) { + throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); + } + try { + ReflectUtils.findConstructor(localClass, interfaceClass); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implemention class " + localClass.getName()); + } + } + if (ConfigUtils.isNotEmpty(stub)) { + Class localClass = ConfigUtils.isDefault(stub) ? ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); + if (! interfaceClass.isAssignableFrom(localClass)) { + throw new IllegalStateException("The stub implemention class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); + } + try { + ReflectUtils.findConstructor(localClass, interfaceClass); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implemention class " + localClass.getName()); + } + } + if (ConfigUtils.isNotEmpty(mock)) { + Class mockClass = ConfigUtils.isDefault(mock) ? ReflectUtils.forName(interfaceClass.getName() + "Mock") : ReflectUtils.forName(mock); + if (! interfaceClass.isAssignableFrom(mockClass)) { + throw new IllegalStateException("The mock implemention class " + mockClass.getName() + " not implement interface " + interfaceClass.getName()); + } + try { + mockClass.getConstructor(new Class[0]); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName()); + } + } + } + + private void checkDefault() { + if (consumer == null) { + consumer = new ConsumerConfig(); + String t = getLegacyProperty("dubbo.service.invoke.timeout"); + if (t != null && t.length() > 0) { + consumer.setTimeout(Integer.parseInt(t.trim())); + } + String r = getLegacyProperty("dubbo.service.max.retry.providers"); + if (r != null && r.length() > 0) { + consumer.setRetries(Integer.parseInt(r.trim()) - 1); + } + String c = getLegacyProperty("dubbo.service.allow.no.provider"); + if (c != null && c.length() > 0) { + consumer.setCheck(!Boolean.parseBoolean(c)); + } + } + } + + public Class getInterfaceClass() { + return interfaceClass == null ? GenericService.class : interfaceClass; + } + + /** + * @deprecated + * @see #setInterface(Class) + * @param interfaceClass + */ + @Deprecated + public void setInterfaceClass(Class interfaceClass) { + setInterface(interfaceClass); + } + + public String getInterface() { + return interfaceName; + } + + public void setInterface(String interfaceName) { + this.interfaceName = interfaceName; + } + + public void setInterface(Class interfaceClass) { + if (interfaceClass != null && ! interfaceClass.isInterface()) { + throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); + } + this.interfaceClass = interfaceClass; + this.interfaceName = interfaceClass == null ? null : interfaceClass.getName(); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + checkName("version", version); + this.version = version; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + checkName("group", group); + this.group = group; + } + + public String getClient() { + return client; + } + + public void setClient(String client) { + checkName("client", client); + this.client = client; + } + + @Parameter(excluded = true) + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public List getMethods() { + return methods; + } + + @SuppressWarnings("unchecked") + public void setMethods(List methods) { + this.methods = (List) methods; + } + + public ConsumerConfig getConsumer() { + return consumer; + } + + public void setConsumer(ConsumerConfig consumer) { + this.consumer = consumer; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java new file mode 100644 index 0000000000..dec15eae3d --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java @@ -0,0 +1,280 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; +import com.alibaba.dubbo.remoting.Transporter; +import com.alibaba.dubbo.rpc.RpcConstants; + +/** + * RegistryConfig + * + * @author william.liangf + */ +public class RegistryConfig extends AbstractConfig { + + private static final long serialVersionUID = 5508512956753757169L; + + public static final String NO_AVAILABLE = "N/A"; + + // 注册中心地址 + private String address; + + // 注册中心登录用户名 + private String username; + + // 注册中心登录密码 + private String password; + + // 注册中心缺省端口 + private Integer port; + + // 注册中心协议 + private String protocol; + + // 客户端实现 + private String transporter; + + private String server; + + private String client; + + private String group; + + private String version; + + // 注册中心请求超时时间(毫秒) + private Integer timeout; + + // 动态注册中心列表存储文件 + private String file; + + // 停止时等候完成通知时间 + private Integer wait; + + // 启动时检查注册中心是否存在 + private Boolean check; + + // 在该注册中心上注册是动态的还是静态的服务 + private Boolean dynamic; + + // 在该注册中心上服务是否暴露 + private Boolean register; + + // 在该注册中心上服务是否引用 + private Boolean subscribe; + + public RegistryConfig() { + } + + public RegistryConfig(String address) { + setAddress(address); + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + checkName("protocol", protocol); + this.protocol = protocol; + } + + @Parameter(excluded = true) + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + checkName("username", username); + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + checkLength("password", password); + this.password = password; + } + + /** + * @deprecated + * @see com.alibaba.dubbo.config.ProviderConfig#getWait() + * @return + */ + @Deprecated + public Integer getWait() { + return wait; + } + + /** + * @deprecated + * @see com.alibaba.dubbo.config.ProviderConfig#setWait(Integer) + * @param wait + */ + @Deprecated + public void setWait(Integer wait) { + this.wait = wait; + if( wait!=null && wait>0) + System.setProperty(RpcConstants.SHUTDOWN_TIMEOUT_KEY, String.valueOf(wait)); + } + + public Boolean isCheck() { + return check; + } + + public void setCheck(Boolean check) { + this.check = check; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + checkPathLength("file", file); + this.file = file; + } + + /** + * @deprecated + * @see #getTransporter() + * @return + */ + @Deprecated + @Parameter(excluded = true) + public String getTransport() { + return getTransporter(); + } + + /** + * @deprecated + * @see #setTransporter(String) + * @param transport + */ + @Deprecated + public void setTransport(String transport) { + setTransporter(transport); + } + + public String getTransporter() { + return transporter; + } + + public void setTransporter(String transporter) { + checkName("transporter", transporter); + if(transporter != null && transporter.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(transporter)){ + throw new IllegalStateException("No such transporter type : " + transporter); + } + this.transporter = transporter; + } + + public String getServer() { + return server; + } + + public void setServer(String server) { + checkName("server", server); + if(server != null && server.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(server)){ + throw new IllegalStateException("No such server type : " + server); + } + this.server = server; + } + + public String getClient() { + return client; + } + + public void setClient(String client) { + checkName("client", client); + if(client != null && client.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(client)){ + throw new IllegalStateException("No such client type : " + client); + } + this.client = client; + } + + public Integer getTimeout() { + return timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public Boolean isDynamic() { + return dynamic; + } + + public void setDynamic(Boolean dynamic) { + this.dynamic = dynamic; + } + + public Boolean isRegister() { + return register; + } + + public void setRegister(Boolean register) { + this.register = register; + } + + public Boolean isSubscribe() { + return subscribe; + } + + public void setSubscribe(Boolean subscribe) { + this.subscribe = subscribe; + } + + public static void closeAll() { + AbstractRegistryFactory.destroyAll(); + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java new file mode 100644 index 0000000000..08ed65c821 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java @@ -0,0 +1,613 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config; + +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcStatus; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * ServiceConfig + * + * @author william.liangf + */ +public class ServiceConfig extends AbstractServiceConfig { + + private static final long serialVersionUID = 3033787999037024738L; + + private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + // 接口类型 + private String interfaceName; + + private Class interfaceClass; + + // 接口实现类引用 + private T ref; + + // 服务名称 + private String path; + + // 方法配置 + private List methods; + + private ProviderConfig provider; + + private final List urls = new ArrayList(); + + private final List> exporters = new ArrayList>(); + + private transient boolean exported; + + private transient boolean unexported; + + private transient boolean generic; + + public boolean isExported() { + return exported; + } + + public synchronized void export() { + export(true); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected synchronized void ready() { + for (URL url : urls) { + RpcStatus.getStatus(url).setReady(true); + } + List registryURLs = loadRegistries(); + if (registryURLs != null && registryURLs.size() > 0) { + for (URL url : urls) { + String providerURL = url.addParameter("enabled", "true").toFullString(); + for (URL registryURL : registryURLs) { + if (logger.isInfoEnabled()) { + logger.info("Register dubbo service " + interfaceClass.getName() + " url " + providerURL + " to registry " + registryURL); + } + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(RpcConstants.EXPORT_KEY, providerURL)); + Exporter exporter = protocol.export(invoker); + exporters.add(exporter); + } + } + } + } + + protected synchronized void export(boolean ready) { + if (unexported) { + throw new IllegalStateException("Already unexported!"); + } + if (exported) { + return; + } + if (interfaceName == null || interfaceName.length() == 0) { + throw new IllegalStateException(" interface not allow null!"); + } + if (provider != null) { + if (application == null) { + application = provider.getApplication(); + } + if (registries == null) { + registries = provider.getRegistries(); + } + if (protocols == null) { + protocols = provider.getProtocols(); + } + } + if (ref instanceof GenericService) { + interfaceClass = GenericService.class; + generic = true; + } else { + try { + interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() + .getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + checkInterface(); + generic = false; + } + if(local !=null){ + if(local=="true"){ + local=interfaceName+"Local"; + } + Class localClass; + try { + localClass = Class.forName(local); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + if(!interfaceClass.isAssignableFrom(localClass)){ + throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName); + } + } + if(stub !=null){ + if(stub=="true"){ + stub=interfaceName+"Stub"; + } + Class stubClass; + try { + stubClass = Class.forName(stub); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + if(!interfaceClass.isAssignableFrom(stubClass)){ + throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName); + } + } + checkApplication(); + checkRegistry(); + checkProtocol(); + if (path == null || path.length() == 0) { + path = interfaceName; + } + doExportUrls(); + boolean r = (ready && (delay == null || delay <= 0)); + for (URL url : urls) { + RpcStatus.getStatus(url).setReady(r); + } + doExport(r); + if (delay != null && delay > 0) { + Thread thread = new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(delay); + } catch (Throwable e) { + } + ready(); + } + }); + thread.setDaemon(true); + thread.setName("DelayExportServiceThread"); + thread.start(); + } + exported = true; + } + + private void checkInterface() { + // 检查接口不为空,并且类型必需为接口 + if (interfaceClass == null) { + throw new IllegalStateException("interface not allow null!"); + } + // 检查引用不为空,并且引用必需实现接口 + if (ref == null) { + throw new IllegalStateException("ref not allow null!"); + } + if (! interfaceClass.isInstance(ref)) { + throw new IllegalStateException("The class " + + ref.getClass().getName() + " unimplemented interface " + + interfaceClass + "!"); + } + // 检查方法是否在接口中存在 + if (methods != null && methods.size() > 0) { + for (MethodConfig methodBean : methods) { + String methodName = methodBean.getName(); + if (methodName == null || methodName.length() == 0) { + throw new IllegalStateException(" name attribute is required! Please check: "); + } + boolean hasMethod = false; + for (java.lang.reflect.Method method : interfaceClass.getMethods()) { + if (method.getName().equals(methodName)) { + hasMethod = true; + break; + } + } + if (!hasMethod) { + throw new IllegalStateException("The interface " + interfaceClass.getName() + + " not found method " + methodName); + } + } + } + if (ConfigUtils.isNotEmpty(stub)) { + Class localClass = ConfigUtils.isDefault(stub) ? ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); + if (! interfaceClass.isAssignableFrom(localClass)) { + throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); + } + try { + ReflectUtils.findConstructor(localClass, interfaceClass); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implemention class " + localClass.getName()); + } + } + if (ConfigUtils.isNotEmpty(mock)) { + Class mockClass = ConfigUtils.isDefault(mock) ? ReflectUtils.forName(interfaceClass.getName() + "Mock") : ReflectUtils.forName(mock); + if (! interfaceClass.isAssignableFrom(mockClass)) { + throw new IllegalStateException("The mock implemention class " + mockClass.getName() + " not implement interface " + interfaceClass.getName()); + } + try { + mockClass.getConstructor(new Class[0]); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName()); + } + } + } + + public synchronized void unexport() { + if (unexported) { + throw new IllegalStateException("Already unexported!"); + } + unexported = true; + if (exporters != null && exporters.size() > 0) { + for (Exporter exporter : exporters) { + try { + exporter.unexport(); + } catch (Throwable t) { + logger.warn("unexpected err when unexport" + exporter, t); + } + } + exporters.clear(); + } + } + + private void doExportUrls() { + for (ProtocolConfig protocolConfig : protocols) { + String name = protocolConfig.getName(); + if (name == null || name.length() == 0) { + name = "dubbo"; + } + String host = protocolConfig.getHost(); + if (provider != null && (host == null || host.length() == 0)) { + host = provider.getHost(); + } + boolean anyhost = false; + if (NetUtils.isInvalidLocalHost(host)) { + anyhost = true; + try { + host = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + logger.warn(e.getMessage(), e); + } + if (NetUtils.isInvalidLocalHost(host)) { + List registryURLs = loadRegistries(); + if (registryURLs != null && registryURLs.size() > 0) { + for (URL registryURL : registryURLs) { + try { + Socket socket = new Socket(registryURL.getHost(), registryURL.getPort()); + try { + host = socket.getLocalAddress().getHostAddress(); + break; + } finally { + socket.close(); + } + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + } + if (NetUtils.isInvalidLocalHost(host)) { + host = NetUtils.getLocalHost(); + } + } + } + Integer port = protocolConfig.getPort(); + if (provider != null && (port == null || port == 0)) { + port = provider.getPort(); + } + if (port == null || port == 0) { + port = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); + } + if (port == null || port <= 0) { + port = NetUtils.getAvailablePort(); + logger.warn("Use random available port(" + port + ") for protocol " + name); + } + Map map = new HashMap(); + if (anyhost) { + map.put(Constants.ANYHOST_KEY, "true"); + } + map.put("dubbo", Version.getVersion()); + appendParameters(map, application); + appendParameters(map, provider); + appendParameters(map, protocolConfig); + appendParameters(map, this); + map.put("prompt", "dubbo"); + if (methods != null && methods.size() > 0) { + for (MethodConfig method : methods) { + appendParameters(map, method, method.getName()); + List arguments = method.getArguments(); + if (arguments != null && arguments.size() > 0) { + for (ArgumentConfig argument : arguments) { + //类型自动转换. + if(argument.getType() != null && argument.getType().length() >0){ + Method[] methods = interfaceClass.getMethods(); + //遍历所有方法 + if(methods != null && methods.length > 0){ + for (int i = 0; i < methods.length; i++) { + String methodName = methods[i].getName(); + //匹配方法名称,获取方法签名. + if(methodName.equals(method.getName())){ + Class[] argtypes = methods[i].getParameterTypes(); + //一个方法中单个callback + if (argument.getIndex() != -1 ){ + if (argtypes[argument.getIndex()].getName().equals(argument.getType())){ + appendParameters(map, argument, method.getName() + "." + argument.getIndex()); + }else { + throw new IllegalArgumentException("argument config error : the index attribute and type attirbute not match :index :"+argument.getIndex() + ", type:" + argument.getType()); + } + } else { + //一个方法中多个callback + for (int j = 0 ;j argclazz = argtypes[j]; + if (argclazz.getName().equals(argument.getType())){ + appendParameters(map, argument, method.getName() + "." + j); + if (argument.getIndex() != -1 && argument.getIndex() != j){ + throw new IllegalArgumentException("argument config error : the index attribute and type attirbute not match :index :"+argument.getIndex() + ", type:" + argument.getType()); + } + } + } + } + } + } + } + }else if(argument.getIndex() != -1){ + appendParameters(map, argument, method.getName() + "." + argument.getIndex()); + }else { + throw new IllegalArgumentException("argument config must set index or type attribute.eg: or "); + } + + } + } + } + } + if (generic) { + map.put("generic", "true"); + map.put("methods", "*"); + } else { + map.put("revision", Version.getVersion(interfaceClass, version)); + map.put("methods", StringUtils.join(new HashSet(Arrays.asList(Wrapper.getWrapper(interfaceClass).getDeclaredMethodNames())), ",")); + } + if (! ConfigUtils.isEmpty(token)) { + if (ConfigUtils.isDefault(token)) { + map.put("token", UUID.randomUUID().toString()); + } else { + map.put("token", token); + } + } + if ("injvm".equals(protocolConfig.getName())) { + map.put("notify", "false"); + } + // 导出服务 + String contextPath = protocolConfig.getContextpath(); + if ((contextPath == null || contextPath.length() == 0) && provider != null) { + contextPath = provider.getContextpath(); + } + URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map); + this.urls.add(url); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void doExport(boolean ready) { + List registryURLs = loadRegistries(); + for (URL url : urls) { + if (logger.isInfoEnabled()) { + logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); + } + if (registryURLs != null && registryURLs.size() > 0) { + for (URL registryURL : registryURLs) { + String providerURL = url.addParameter("enabled", String.valueOf(ready)).addParameter(Constants.MONITOR_KEY, + convertMonitor(url.getParameter(Constants.MONITOR_KEY), registryURL)).toFullString(); + if (logger.isInfoEnabled()) { + logger.info("Register dubbo service " + interfaceClass.getName() + " url " + providerURL + " to registry " + registryURL); + } + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(RpcConstants.EXPORT_KEY, providerURL)); + Exporter exporter = protocol.export(invoker); + exporters.add(exporter); + } + } else { + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); + Exporter exporter = protocol.export(invoker); + exporters.add(exporter); + } + } + } + + private void checkProtocol() { + if ((protocols == null || protocols.size() == 0) + && provider != null) { + setProtocols(provider.getProtocols()); + } + // 兼容旧版本 + if (protocols == null || protocols.size() == 0) { + ProtocolConfig providerBean = new ProtocolConfig(); + String p = getLegacyProperty("dubbo.service.protocol"); + if (p != null && p.length() > 0) { + providerBean.setName(p); + } + String h = getLegacyProperty("dubbo.service.server.host"); + if (h != null && h.length() > 0) { + providerBean.setHost(h); + } + String o = getLegacyProperty("dubbo.service.server.port"); + if (o != null && o.length() > 0) { + providerBean.setPort(Integer.parseInt(o.trim())); + } + String t = getLegacyProperty("dubbo.service.max.thread.pool.size"); + if (t != null && t.length() > 0) { + providerBean.setThreads(Integer.parseInt(t.trim())); + } + setProtocol(providerBean); + } + } + + public Class getInterfaceClass() { + return interfaceClass == null ? GenericService.class : interfaceClass; + } + + /** + * @deprecated + * @see #setInterface(Class) + * @param interfaceClass + */ + public void setInterfaceClass(Class interfaceClass) { + setInterface(interfaceClass); + } + + public String getInterface() { + return interfaceName; + } + + public void setInterface(String interfaceName) { + this.interfaceName = interfaceName; + } + + public void setInterface(Class interfaceClass) { + if (interfaceClass != null && ! interfaceClass.isInterface()) { + throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); + } + this.interfaceClass = interfaceClass; + this.interfaceName = interfaceClass == null ? null : interfaceClass.getName(); + } + + public T getRef() { + return ref; + } + + public void setRef(T ref) { + this.ref = ref; + } + + @Parameter(excluded = true) + public String getPath() { + return path; + } + + public void setPath(String path) { + checkPathName("path", path); + this.path = path; + } + + public List getMethods() { + return methods; + } + + @SuppressWarnings("unchecked") + public void setMethods(List methods) { + this.methods = (List) methods; + } + + public ProviderConfig getProvider() { + return provider; + } + + public void setProvider(ProviderConfig provider) { + this.provider = provider; + } + + public List getExportedUrls(){ + return urls; + } + + // ======== Deprecated ======== + + /** + * @deprecated Replace to getProtocols() + */ + @Deprecated + public List getProviders() { + return convertProtocolToProvider(protocols); + } + + /** + * @deprecated Replace to setProtocols() + */ + @Deprecated + public void setProviders(List providers) { + this.protocols = convertProviderToProtocol(providers); + } + + @Deprecated + private static final List convertProviderToProtocol(List providers) { + if (providers == null || providers.size() == 0) { + return null; + } + List protocols = new ArrayList(providers.size()); + for (ProviderConfig provider : providers) { + protocols.add(convertProviderToProtocol(provider)); + } + return protocols; + } + + @Deprecated + private static final List convertProtocolToProvider(List protocols) { + if (protocols == null || protocols.size() == 0) { + return null; + } + List providers = new ArrayList(protocols.size()); + for (ProtocolConfig provider : protocols) { + providers.add(convertProtocolToProvider(provider)); + } + return providers; + } + + @Deprecated + private static final ProtocolConfig convertProviderToProtocol(ProviderConfig provider) { + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName(provider.getProtocol().getName()); + protocol.setServer(provider.getServer()); + protocol.setClient(provider.getClient()); + protocol.setCodec(provider.getCodec()); + protocol.setHost(provider.getHost()); + protocol.setPort(provider.getPort()); + protocol.setPath(provider.getPath()); + protocol.setPayload(provider.getPayload()); + protocol.setThreads(provider.getThreads()); + protocol.setParameters(provider.getParameters()); + return protocol; + } + + @Deprecated + private static final ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) { + ProviderConfig provider = new ProviderConfig(); + provider.setProtocol(protocol); + provider.setServer(protocol.getServer()); + provider.setClient(protocol.getClient()); + provider.setCodec(protocol.getCodec()); + provider.setHost(protocol.getHost()); + provider.setPort(protocol.getPort()); + provider.setPath(protocol.getPath()); + provider.setPayload(protocol.getPayload()); + provider.setThreads(protocol.getThreads()); + provider.setParameters(protocol.getParameters()); + return provider; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java new file mode 100644 index 0000000000..18ffdd6cf3 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java @@ -0,0 +1,149 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.spring; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ConsumerConfig; +import com.alibaba.dubbo.config.MonitorConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.ReferenceConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; +import com.alibaba.dubbo.rpc.injvm.InjvmProtocol; + +/** + * ReferenceFactoryBean + * + * @author william.liangf + */ +public class ReferenceBean extends ReferenceConfig implements FactoryBean, ApplicationContextAware { + + private static final long serialVersionUID = 213195494150089726L; + + private transient ApplicationContext applicationContext; + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + private static boolean isEquals(String s1, String s2) { + if (s1 == null && s2 == null) { + return true; + } + if (s1 == null || s2 == null) { + return false; + } + return s1.equals(s2); + } + + @SuppressWarnings({ "unchecked"}) + public Object getObject() throws Exception { + if (getConsumer() == null) { + Map consumerConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(ConsumerConfig.class, false, false); + if (consumerConfigMap != null && consumerConfigMap.size() > 0) { + ConsumerConfig consumerConfig = null; + Collection defaultConfigs = consumerConfigMap.values(); + for (ConsumerConfig config : defaultConfigs) { + if (config.getClass() == ConsumerConfig.class) { + if (consumerConfig != null) { + throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config); + } + consumerConfig = config; + } + } + if (consumerConfig != null) { + setConsumer(consumerConfig); + } + } + } + if (getApplication() == null + && (getConsumer() == null || getConsumer().getApplication() == null)) { + Map applicationConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(ApplicationConfig.class, false, false); + if (applicationConfigMap != null && applicationConfigMap.size() > 0) { + if (applicationConfigMap.size() > 1) { + throw new IllegalStateException("Duplicate application configs: " + applicationConfigMap.values()); + } + ApplicationConfig applicationConfig = applicationConfigMap.values().iterator().next(); + setApplication(applicationConfig); + } + } + if (getRegistries() == null || getRegistries().size() == 0 + && (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().size() == 0)) { + Map registryConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(RegistryConfig.class, false, false); + if (registryConfigMap != null && registryConfigMap.size() > 0) { + Collection registryConfigs = registryConfigMap.values(); + if (registryConfigs != null && registryConfigs.size() > 0) { + super.setRegistries(new ArrayList(registryConfigs)); + } + } + } + if (getMonitor() == null + && (getConsumer() == null || getConsumer().getMonitor() == null)) { + Map monitorConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(MonitorConfig.class, false, false); + if (monitorConfigMap != null && monitorConfigMap.size() > 0) { + if (monitorConfigMap.size() > 1) { + throw new IllegalStateException("Duplicate monitor configs: " + monitorConfigMap.values()); + } + MonitorConfig monitorConfig = monitorConfigMap.values().iterator().next(); + super.setMonitor(monitorConfig.getAddress()); + } + } + if (isInjvm() == null + && (getConsumer() == null || getConsumer().isInjvm() == null) + && applicationContext != null) { + Map> serviceConfigMap = applicationContext.getBeansOfType(ServiceConfig.class); + if (serviceConfigMap != null && serviceConfigMap.size() > 0) { + for (ServiceConfig serviceConfig : serviceConfigMap.values()) { + if (isEquals(serviceConfig.getInterface(), getInterface()) + && isEquals(serviceConfig.getVersion(), getVersion()) + && isEquals(serviceConfig.getGroup(), getGroup())) { + List protocols = serviceConfig.getProtocols(); + if ((protocols == null || protocols.size() == 0) + && serviceConfig.getProvider() != null) { + protocols = serviceConfig.getProvider().getProtocols(); + } + for (ProtocolConfig protocol : protocols) { + if (InjvmProtocol.NAME.equals(protocol.getName())) { + setInjvm(true); + break; + } + } + break; + } + } + } + } + return get(); + } + + public Class getObjectType() { + return getInterfaceClass(); + } + + public boolean isSingleton() { + return true; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java new file mode 100644 index 0000000000..060639c691 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java @@ -0,0 +1,173 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.spring; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.MonitorConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.ProviderConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; + +/** + * ServiceFactoryBean + * + * @author william.liangf + */ +public class ServiceBean extends ServiceConfig implements InitializingBean, ApplicationContextAware, ApplicationListener, BeanNameAware { + + private static final long serialVersionUID = 213195494150089726L; + + private static transient ApplicationContext SPRING_CONTEXT; + + private transient ApplicationContext applicationContext; + + private transient String beanName; + + private transient boolean supportedApplicationListener; + + public static ApplicationContext getSpringContext() { + return SPRING_CONTEXT; + } + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + if (applicationContext != null) { + SPRING_CONTEXT = applicationContext; + try { + Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class[]{ApplicationListener.class}); // 兼容Spring2.0.1 + method.invoke(applicationContext, new Object[] {this}); + supportedApplicationListener = true; + } catch (Throwable t) { + } + } + } + + public void setBeanName(String name) { + this.beanName = name; + } + + public void onApplicationEvent(ApplicationEvent event) { + if ("org.springframework.context.event.ContextStartedEvent".equals(event.getClass().getName())) { // 兼容Spring2.0.1 + if (isDelay()) { + if (logger.isInfoEnabled()) { + logger.info("The service ready on spring started. service: " + getInterface()); + } + ready(); + } + } + } + + private boolean isDelay() { + Integer delay = getDelay(); + ProviderConfig provider = getProvider(); + if (delay == null && provider != null) { + delay = provider.getDelay(); + } + return supportedApplicationListener && delay != null && delay.intValue() == -1; + } + + @SuppressWarnings({ "unchecked" }) + public void afterPropertiesSet() throws Exception { + if (getProvider() == null) { + Map providerConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(ProviderConfig.class, false, false); + if (providerConfigMap != null && providerConfigMap.size() > 0) { + Collection providerConfigs = providerConfigMap.values(); + ProviderConfig providerConfig = providerConfigs.iterator().next(); + if (providerConfigs.size() > 1) { + Map protocolConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(ProtocolConfig.class, false, false); + if (protocolConfigMap != null && protocolConfigMap.size() > 0) { + throw new IllegalStateException("Duplicate provider configs: " + providerConfigs); + } + for (ProviderConfig config : providerConfigs) { + if (config.isDefault() != null && config.isDefault()) { + providerConfig = config; + } + } + } + setProvider(providerConfig); + } + } + if (getApplication() == null + && (getProvider() == null || getProvider().getApplication() == null)) { + Map applicationConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(ApplicationConfig.class, false, false); + if (applicationConfigMap != null && applicationConfigMap.size() > 0) { + if (applicationConfigMap.size() > 1) { + throw new IllegalStateException("Duplicate application configs: " + applicationConfigMap.values()); + } + ApplicationConfig applicationConfig = applicationConfigMap.values().iterator().next(); + setApplication(applicationConfig); + } + } + if (getRegistries() == null || getRegistries().size() == 0 + && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().size() == 0)) { + Map registryConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(RegistryConfig.class, false, false); + if (registryConfigMap != null && registryConfigMap.size() > 0) { + Collection registryConfigs = registryConfigMap.values(); + if (registryConfigs != null && registryConfigs.size() > 0) { + super.setRegistries(new ArrayList(registryConfigs)); + } + } + } + if (getMonitor() == null + && (getProvider() == null || getProvider().getMonitor() == null)) { + Map monitorConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(MonitorConfig.class, false, false); + if (monitorConfigMap != null && monitorConfigMap.size() > 0) { + if (monitorConfigMap.size() > 1) { + throw new IllegalStateException("Duplicate monitor configs: " + monitorConfigMap.values()); + } + MonitorConfig monitorConfig = monitorConfigMap.values().iterator().next(); + super.setMonitor(monitorConfig.getAddress()); + } + } + if ((getProtocols() == null || getProtocols().size() == 0) + && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().size() == 0)) { + Map protocolConfigMap = applicationContext == null ? null : applicationContext.getBeansOfType(ProtocolConfig.class, false, false); + if (protocolConfigMap != null && protocolConfigMap.size() > 0) { + Collection protocolConfigs = protocolConfigMap.values(); + if (protocolConfigs != null && protocolConfigs.size() > 0) { + setProtocols(new ArrayList(protocolConfigs)); + } + } + } + if (getPath() == null || getPath().length() == 0) { + if (beanName != null && beanName.length() > 0 + && getInterface() != null && getInterface().length() > 0 + && beanName.startsWith(getInterface())) { + setPath(beanName); + } + } + Integer delay = getDelay(); + ProviderConfig provider = getProvider(); + if (delay == null && provider != null) { + delay = provider.getDelay(); + } + export(! isDelay()); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java new file mode 100644 index 0000000000..20f7cde652 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboBeanDefinitionParser.java @@ -0,0 +1,330 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.spring.schema; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Date; + +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.ArgumentConfig; +import com.alibaba.dubbo.config.MethodConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.rpc.Protocol; + +/** + * AbstractBeanDefinitionParser + * + * @author william.liangf + */ +public class DubboBeanDefinitionParser implements BeanDefinitionParser { + + private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class); + + private final Class beanClass; + + private final boolean required; + + public DubboBeanDefinitionParser(Class beanClass, boolean required) { + this.beanClass = beanClass; + this.required = required; + } + + public BeanDefinition parse(Element element, ParserContext parserContext) { + return parse(element, parserContext, beanClass, required); + } + + private static BeanDefinition parse(Element element, ParserContext parserContext, Class beanClass, boolean required) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(); + beanDefinition.setBeanClass(beanClass); + beanDefinition.setLazyInit(false); + String id = element.getAttribute("id"); + if ((id == null || id.length() == 0) && required) { + String generatedBeanName = element.getAttribute("name"); + if (generatedBeanName == null || generatedBeanName.length() == 0) { + generatedBeanName = element.getAttribute("interface"); + } + if (generatedBeanName == null || generatedBeanName.length() == 0) { + generatedBeanName = beanClass.getName(); + } + id = generatedBeanName; + int counter = 2; + while(parserContext.getRegistry().containsBeanDefinition(id)) { + id = generatedBeanName + (counter ++); + } + } + if (id != null && id.length() > 0) { + if (parserContext.getRegistry().containsBeanDefinition(id)) { + throw new IllegalStateException("Duplicate spring bean id " + id); + } + parserContext.getRegistry().registerBeanDefinition(id, beanDefinition); + } + if (ProtocolConfig.class.equals(beanClass)) { + for (String name : parserContext.getRegistry().getBeanDefinitionNames()) { + BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name); + PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol"); + if (property != null) { + Object value = property.getValue(); + if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) { + definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id)); + } + } + } + } + for (Method setter : beanClass.getMethods()) { + String name = setter.getName(); + if (name.length() > 3 && name.startsWith("set") + && Modifier.isPublic(setter.getModifiers()) + && setter.getParameterTypes().length == 1) { + Class type = setter.getParameterTypes()[0]; + String property = name.substring(3, 4).toLowerCase() + name.substring(4); + Method getter = null; + try { + getter = beanClass.getMethod("get" + name.substring(3), new Class[0]); + } catch (NoSuchMethodException e) { + try { + getter = beanClass.getMethod("is" + name.substring(3), new Class[0]); + } catch (NoSuchMethodException e2) { + } + } + if (getter == null + || ! Modifier.isPublic(getter.getModifiers()) + || ! type.equals(getter.getReturnType())) { + continue; + } + if ("parameters".equals(property)) { + parseParameters(element.getChildNodes(), beanDefinition); + } else if ("methods".equals(property)) { + parseMethods(id, element.getChildNodes(), beanDefinition, parserContext); + } else if ("arguments".equals(property)) { + parseArguments(id, element.getChildNodes(), beanDefinition, parserContext); + } else { + String value = element.getAttribute(property); + if (value != null) { + value = value.trim(); + if (value.length() > 0) { + if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress(RegistryConfig.NO_AVAILABLE); + beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig); + } else if ("registry".equals(property) && value.indexOf(',') != -1) { + parseMultiRef("registries", value, beanDefinition, parserContext); + } else if ("provider".equals(property) && value.indexOf(',') != -1) { + parseMultiRef("providers", value, beanDefinition, parserContext); + } else if ("protocol".equals(property) && value.indexOf(',') != -1) { + parseMultiRef("protocols", value, beanDefinition, parserContext); + } else { + Object reference; + if (isPrimitive(type)) { + if ("async".equals(property) && "false".equals(value) + || "timeout".equals(property) && "0".equals(value) + || "delay".equals(property) && "0".equals(value) + || "version".equals(property) && "0.0.0".equals(value) + || "stat".equals(property) && "-1".equals(value) + || "reliable".equals(property) && "false".equals(value)) { + // 兼容旧版本xsd中的default值 + value = null; + } + reference = value; + if (! "id".equals(property) + && ! "name".equals(property) + && ! "interface".equals(property)) { + String sysProperty = element.getPrefix() + "." + element.getLocalName() + "." + id + "." + property; + String sysValue = System.getProperty(sysProperty); + if (sysValue != null && sysValue.trim().length() > 0) { + reference = sysValue.trim(); + } else { + sysProperty = element.getPrefix() + "." + element.getLocalName() + "." + property; + sysValue = System.getProperty(sysProperty); + if (sysValue != null && sysValue.trim().length() > 0) { + reference = sysValue.trim(); + } + } + } + } else if ("protocol".equals(property) + && ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value) + && (! parserContext.getRegistry().containsBeanDefinition(value) + || ! ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) { + if ("dubbo:provider".equals(element.getTagName())) { + logger.warn("Recommended replace to "); + } + // 兼容旧版本配置 + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName(value); + reference = protocol; + } else if ("onreturn".equals(property)) { + int index = value.lastIndexOf("."); + String returnRef = value.substring(0, index); + String returnMethod = value.substring(index + 1); + reference = new RuntimeBeanReference(returnRef); + beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod); + } else if ("onthrow".equals(property)) { + int index = value.lastIndexOf("."); + String throwRef = value.substring(0, index); + String throwMethod = value.substring(index + 1); + reference = new RuntimeBeanReference(throwRef); + beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod); + } else { + if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) { + BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value); + if (! refBean.isSingleton()) { + throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value + " bean scope to singleton, eg: "); + } + } + reference = new RuntimeBeanReference(value); + } + beanDefinition.getPropertyValues().addPropertyValue(property, reference); + } + } + } + } + } + } + return beanDefinition; + } + + private static boolean isPrimitive(Class cls) { + return cls.isPrimitive() || cls == Boolean.class || cls == Byte.class + || cls == Character.class || cls == Short.class || cls == Integer.class + || cls == Long.class || cls == Float.class || cls == Double.class + || cls == String.class || cls == Date.class || cls == Class.class; + } + + @SuppressWarnings("unchecked") + private static void parseMultiRef(String property, String value, RootBeanDefinition beanDefinition, + ParserContext parserContext) { + String[] values = value.split("\\s*[,]+\\s*"); + ManagedList list = null; + for (int i = 0; i < values.length; i++) { + String v = values[i]; + if (v != null && v.length() > 0) { + if (list == null) { + list = new ManagedList(); + } + list.add(new RuntimeBeanReference(v)); + } + } + beanDefinition.getPropertyValues().addPropertyValue(property, list); + } + + @SuppressWarnings("unchecked") + private static void parseParameters(NodeList nodeList, RootBeanDefinition beanDefinition) { + if (nodeList != null && nodeList.getLength() > 0) { + ManagedMap parameters = null; + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node instanceof Element) { + if ("parameter".equals(node.getNodeName()) + || "parameter".equals(node.getLocalName())) { + if (parameters == null) { + parameters = new ManagedMap(); + } + String key = ((Element) node).getAttribute("key"); + String value = ((Element) node).getAttribute("value"); + boolean hide = "true".equals(((Element) node).getAttribute("hide")); + if (hide) { + key = Constants.HIDE_KEY_PREFIX + key; + } + parameters.put(key, new TypedStringValue(value, String.class)); + } + } + } + if (parameters != null) { + beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters); + } + } + } + + @SuppressWarnings("unchecked") + private static void parseMethods(String id, NodeList nodeList, RootBeanDefinition beanDefinition, + ParserContext parserContext) { + if (nodeList != null && nodeList.getLength() > 0) { + ManagedList methods = null; + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node instanceof Element) { + Element element = (Element) node; + if ("method".equals(node.getNodeName()) || "method".equals(node.getLocalName())) { + String methodName = element.getAttribute("name"); + if (methodName == null || methodName.length() == 0) { + throw new IllegalStateException(" name attribute == null"); + } + if (methods == null) { + methods = new ManagedList(); + } + BeanDefinition methodBeanDefinition = parse(((Element) node), + parserContext, MethodConfig.class, false); + String name = id + "." + methodName; + BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder( + methodBeanDefinition, name); + methods.add(methodBeanDefinitionHolder); + } + } + } + if (methods != null) { + beanDefinition.getPropertyValues().addPropertyValue("methods", methods); + } + } + } + + @SuppressWarnings("unchecked") + private static void parseArguments(String id, NodeList nodeList, RootBeanDefinition beanDefinition, + ParserContext parserContext) { + if (nodeList != null && nodeList.getLength() > 0) { + ManagedList arguments = null; + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node instanceof Element) { + Element element = (Element) node; + if ("argument".equals(node.getNodeName()) || "argument".equals(node.getLocalName())) { + String argumentIndex = element.getAttribute("index"); + if (arguments == null) { + arguments = new ManagedList(); + } + BeanDefinition argumentBeanDefinition = parse(((Element) node), + parserContext, ArgumentConfig.class, false); + String name = id + "." + argumentIndex; + BeanDefinitionHolder argumentBeanDefinitionHolder = new BeanDefinitionHolder( + argumentBeanDefinition, name); + arguments.add(argumentBeanDefinitionHolder); + } + } + } + if (arguments != null) { + beanDefinition.getPropertyValues().addPropertyValue("arguments", arguments); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboNamespaceHandler.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboNamespaceHandler.java new file mode 100644 index 0000000000..5ca298ad20 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/schema/DubboNamespaceHandler.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.spring.schema; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ConsumerConfig; +import com.alibaba.dubbo.config.MonitorConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.ProviderConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.spring.ReferenceBean; +import com.alibaba.dubbo.config.spring.ServiceBean; + +/** + * DubboNamespaceHandler + * + * @author william.liangf + */ +public class DubboNamespaceHandler extends NamespaceHandlerSupport { + + static { + Version.checkDuplicate(DubboNamespaceHandler.class); + } + + public void init() { + registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true)); + registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true)); + registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true)); + registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true)); + registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true)); + registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true)); + registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true)); + registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false)); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java new file mode 100644 index 0000000000..1e756d715f --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java @@ -0,0 +1,91 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.spring.status; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.context.ApplicationContext; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.config.spring.ServiceBean; + +/** + * DataSourceStatusChecker + * + * @author william.liangf + */ +@Extension("datasource") +public class DataSourceStatusChecker implements StatusChecker { + + private static final Logger logger = LoggerFactory.getLogger(DataSourceStatusChecker.class); + + @SuppressWarnings("unchecked") + public Status check() { + ApplicationContext context = ServiceBean.getSpringContext(); + if (context == null) { + return new Status(Status.Level.UNKNOWN); + } + Map dataSources = context.getBeansOfType(DataSource.class, false, false); + if (dataSources == null || dataSources.size() == 0) { + return new Status(Status.Level.UNKNOWN); + } + Status.Level level = Status.Level.OK; + StringBuilder buf = new StringBuilder(); + for (Map.Entry entry : dataSources.entrySet()) { + DataSource dataSource = entry.getValue(); + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(entry.getKey()); + try { + Connection connection = dataSource.getConnection(); + try { + DatabaseMetaData metaData = connection.getMetaData(); + ResultSet resultSet = metaData.getTypeInfo(); + try { + if (! resultSet.next()) { + level = Status.Level.ERROR; + } + } finally { + resultSet.close(); + } + buf.append(metaData.getURL()); + buf.append("("); + buf.append(metaData.getDatabaseProductName()); + buf.append("-"); + buf.append(metaData.getDatabaseProductVersion()); + buf.append(")"); + } finally { + connection.close(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + return new Status(level, e.getMessage()); + } + } + return new Status(level, buf.toString()); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java new file mode 100644 index 0000000000..f2f8504364 --- /dev/null +++ b/dubbo-config/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java @@ -0,0 +1,94 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.spring.status; + +import java.lang.reflect.Method; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.Lifecycle; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.config.spring.ServiceBean; + +/** + * SpringStatusChecker + * + * @author william.liangf + */ +@Extension("spring") +public class SpringStatusChecker implements StatusChecker { + + private static final Logger logger = LoggerFactory.getLogger(SpringStatusChecker.class); + + public Status check() { + ApplicationContext context = ServiceBean.getSpringContext(); + if (context == null) { + return new Status(Status.Level.UNKNOWN); + } + Status.Level level = Status.Level.OK; + if (context instanceof Lifecycle) { + if (((Lifecycle)context).isRunning()) { + level = Status.Level.OK; + } else { + level = Status.Level.ERROR; + } + } else { + level = Status.Level.UNKNOWN; + } + StringBuilder buf = new StringBuilder(); + try { + Class cls = context.getClass(); + Method method = null; + while (cls != null && method == null) { + try { + method = cls.getDeclaredMethod("getConfigLocations", new Class[0]); + } catch (NoSuchMethodException t) { + cls = cls.getSuperclass(); + } + } + if (method != null) { + if (! method.isAccessible()) { + method.setAccessible(true); + } + String[] configs = (String[]) method.invoke(context, new Object[0]); + if (configs != null && configs.length > 0) { + String dubboConfig = configs[0]; + for (String config : configs) { + if (config.contains("dubbo") + || config.contains("provider") + || config.contains("server")) { + dubboConfig = config; + break; + } + } + int i = dubboConfig.lastIndexOf('/'); + if (i > 0) { + dubboConfig = dubboConfig.substring(i + 1); + } + buf.append(dubboConfig); + } + } + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + return new Status(level, buf.toString()); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker b/dubbo-config/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker new file mode 100644 index 0000000000..4c153f9c39 --- /dev/null +++ b/dubbo-config/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker @@ -0,0 +1,2 @@ +com.alibaba.dubbo.config.spring.status.SpringStatusChecker +com.alibaba.dubbo.config.spring.status.DataSourceStatusChecker \ No newline at end of file diff --git a/dubbo-config/src/main/resources/META-INF/spring.handlers b/dubbo-config/src/main/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..33510e68c2 --- /dev/null +++ b/dubbo-config/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler \ No newline at end of file diff --git a/dubbo-config/src/main/resources/META-INF/spring.schemas b/dubbo-config/src/main/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..364e467204 --- /dev/null +++ b/dubbo-config/src/main/resources/META-INF/spring.schemas @@ -0,0 +1 @@ +http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=com/alibaba/dubbo/config/spring/schema/dubbo.xsd \ No newline at end of file diff --git a/dubbo-config/src/main/resources/com/alibaba/dubbo/config/spring/schema/dubbo.xsd b/dubbo-config/src/main/resources/com/alibaba/dubbo/config/spring/schema/dubbo.xsd new file mode 100644 index 0000000000..c2945c6bac --- /dev/null +++ b/dubbo-config/src/main/resources/com/alibaba/dubbo/config/spring/schema/dubbo.xsd @@ -0,0 +1,857 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/CallbackTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/CallbackTest.java new file mode 100644 index 0000000000..d043494504 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/CallbackTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.explicit.test; + + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.registry.support.SimpleRegistryExporter; + +/** + * @author chao.liuc + * + */ +public class CallbackTest { + //test 开关 + private boolean test = true ; + + @Before + public void setUp() throws Exception { + test = false; + SimpleRegistryExporter.exportIfAbsent(9234); + } + + @Test + public void startProvider() throws InterruptedException{ + if (!test) return; + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:com/alibaba/dubbo/callback/explicit/provider.xml"); + context.start(); + synchronized (CallbackTest.class) { + CallbackTest.class.wait(); + } + } + + @Test + public void startConsumer() throws InterruptedException{ + if (!test) return; + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:com/alibaba/dubbo/callback/explicit/consumer.xml"); + context.start(); + + IDemoService demoService = (IDemoService)context.getBean("demoService"); + + IDemoCallback callback = new IDemoCallback(){ + public String yyy(String msg) { + System.out.println("callback1:"+msg); + return "callback1 onChanged ,"+msg; + } + }; + + IDemoCallback callback2 = new IDemoCallback(){ + public String yyy(String msg) { + System.out.println("callback2:"+msg); + return "callback2 onChanged ,"+msg; + } + }; + + int i = 1; + long time = System.currentTimeMillis(); + System.out.println("cient request id:"+time); + demoService.xxx(callback,"time:"+(i++) +",client request id:"+time); + Thread.sleep(2500); +// demoService.unxxx(callback,"unxxx"); + System.out.println(""); + + time = System.currentTimeMillis(); + System.out.println("cient request id:"+time); + demoService.xxx(callback2,"time:"+(i++) +",client request id:"+time); + Thread.sleep(2500); +// demoService.unxxx(callback2,"unxxx2"); + System.out.println(""); + + time = System.currentTimeMillis(); + System.out.println("cient request id:"+time); + demoService.xxx(callback,"time:"+(i++) +",client request id:"+time); + Thread.sleep(2500); +// demoService.unxxx(callback,"unxxx"); + + synchronized (CallbackTest.class) { + CallbackTest.class.wait(); + } + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/Client.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/Client.java new file mode 100644 index 0000000000..1f557fc6ca --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/Client.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.explicit.test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +public class Client { + private static ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + private static Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + /** + * @param args + */ + public static void main(String[] args) throws Exception { + URL consumerUrl = Server.serviceURL +// .removeParameter("yyy."+Constants.ASYNC_KEY) + ; + + //refer client + Invoker reference = protocol.refer(IDemoService.class, consumerUrl); + IDemoService demoProxy = (IDemoService)proxyFactory.getProxy(reference); + + //registry callback + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + return "ok"; + } + },"other custom args"); + + System.out.println("Async..."); + + synchronized (Client.class) { + Client.class.wait(); + } + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/DemoServiceImpl.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/DemoServiceImpl.java new file mode 100644 index 0000000000..eb8626c489 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/DemoServiceImpl.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.explicit.test; + +/** + * @author chao.liuc + */ +public class DemoServiceImpl implements IDemoService { + public String get(){ + return "ok" ; + } + + public void xxx(final IDemoCallback callback ,String arg1) { + callback.yyy("Sync callback msg .This is callback data. arg1:"+arg1); + Thread t = new Thread(new Runnable() { + public void run() { + for(int i = 0 ;i< 10;i++){ + String ret = callback.yyy("server invoke callback : arg:"+System.currentTimeMillis()); + System.out.println("callback result is :"+ret); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }); + t.setDaemon(true); + t.start(); + System.out.println("xxx invoke complete"); + } + + public void unxxx(IDemoCallback callback, String arg1) { + + } + + public void xxx2(IDemoCallback callback, IDemoCallback callback2, String arg1) { + + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/IDemoCallback.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/IDemoCallback.java new file mode 100644 index 0000000000..2d6a166598 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/IDemoCallback.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.explicit.test; + + +/** + * @author liuchao + * + */ +public interface IDemoCallback{ + + String yyy(String msg); + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/IDemoService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/IDemoService.java new file mode 100644 index 0000000000..ec4f519b86 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/IDemoService.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.explicit.test; + +/** + * @author chao.liuc + */ +public interface IDemoService{ + + public String get(); + + public void xxx(IDemoCallback callback,String arg1); + + public void xxx2(IDemoCallback callback,IDemoCallback callback2,String arg1); + + public void unxxx(IDemoCallback callback,String arg1); + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/Server.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/Server.java new file mode 100644 index 0000000000..e42cdfbbac --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/explicit/test/Server.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.explicit.test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.dubbo.DubboCodec; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +public class Server { + private static ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + private static Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + public final static URL serviceURL = URL.valueOf("dubbo://127.0.0.1:20880/"+IDemoService.class.getName()+"?group=test" + +"&"+Constants.CODEC_KEY+"="+DubboCodec.NAME + +"&"+Constants.DOWNSTREAM_CODEC_KEY+"="+DubboCodec.NAME + +"&xxx.0.callback=true" + +"&timeout="+Integer.MAX_VALUE +// uncomment is unblock invoking + +"&yyy."+Constants.ASYNC_KEY+"=true" + ); + /** + * @param args + */ + public static void main(String[] args) throws Exception { + //export + Invoker invoker = proxyFactory.getInvoker(new DemoServiceImpl(), IDemoService.class, serviceURL); + protocol.export(invoker); + + synchronized (Server.class) { + Server.class.wait(); + } + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/CallbackTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/CallbackTest.java new file mode 100644 index 0000000000..7b863197fa --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/CallbackTest.java @@ -0,0 +1,126 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.registry.support.SimpleRegistryExporter; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * @author chao.liuc + */ +public class CallbackTest { + + @Before + public void setUp() throws Exception { + SimpleRegistryExporter.exportIfAbsent(9234); + } + + public static void main(String[] args) throws InterruptedException { + startProvider(); + synchronized (CallbackTest.class) { + CallbackTest.class.wait(); + } + } + + public static AbstractApplicationContext startProvider() { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:com/alibaba/dubbo/callback/implicit/provider.xml"); + context.start(); + return context ; + } + + @Test + public void TestCallback_Close() throws Exception { + AbstractApplicationContext providerContext = startProvider(); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:com/alibaba/dubbo/callback/implicit/consumer2.xml"); + context.start(); + + IDemoService demoService = (IDemoService) context.getBean("demoService"); + int requestId = 2; + Person ret = demoService.get(requestId); + Assert.assertEquals(requestId, ret.getId()); + context.destroy(); + providerContext.destroy(); + } + + @Test + public void TestCallback_Open() throws Exception { + AbstractApplicationContext providerContext = startProvider(); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:com/alibaba/dubbo/callback/implicit/consumer.xml"); + context.start(); + + IDemoService demoService = (IDemoService) context.getBean("demoService"); + NofifyImpl notify = (NofifyImpl) context.getBean("demoCallback"); + + int requestId = 2; + Person ret = demoService.get(requestId); + Assert.assertEquals(null, ret); + for (int i = 0; i < 10; i++) { + if (!notify.ret.containsKey(requestId)) { + Thread.sleep(200); + } else { + break; + } + } + Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); + + context.destroy(); + providerContext.destroy(); + } + @Test + public void Test_Async_Call() throws Exception { + AbstractApplicationContext providerContext = startProvider(); + + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "classpath:com/alibaba/dubbo/callback/implicit/consumer_async.xml"); + context.start(); + + IDemoService demoService = (IDemoService) context.getBean("demoService"); + + + int requestId1 = 1; + Person ret = demoService.get(requestId1); + Assert.assertEquals(null, ret); + Future p1Future = RpcContext.getContext().getFuture(); + + int requestId2 = 2; + Person ret2 = demoService.get(requestId2); + Assert.assertEquals(null, ret2); + Future p2Future = RpcContext.getContext().getFuture(); + + ret = p1Future.get(1000, TimeUnit.MICROSECONDS); + ret2 = p2Future.get(1000, TimeUnit.MICROSECONDS); + Assert.assertEquals(requestId1, ret.getId()); + Assert.assertEquals(requestId2, ret2.getId()); + + context.destroy(); + providerContext.destroy(); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/ExceptionDemoExService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/ExceptionDemoExService.java new file mode 100644 index 0000000000..1c86ed6864 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/ExceptionDemoExService.java @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +class ExceptionDemoExService implements IDemoService { + public Person get(int id) { + throw new RuntimeException("args is :" + id); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/IDemoService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/IDemoService.java new file mode 100644 index 0000000000..171c051f32 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/IDemoService.java @@ -0,0 +1,20 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +interface IDemoService { + public Person get(int id); +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/Nofify.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/Nofify.java new file mode 100644 index 0000000000..fbf2d52bd1 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/Nofify.java @@ -0,0 +1,21 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +interface Nofify { + public void onreturn(Person msg, Integer id); + public void onthrow(Throwable ex, Integer id); +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/NofifyImpl.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/NofifyImpl.java new file mode 100644 index 0000000000..2d194a022b --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/NofifyImpl.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +import java.util.HashMap; +import java.util.Map; + +class NofifyImpl implements Nofify { + public Map ret = new HashMap(); + public Map errors = new HashMap(); + public void onreturn(Person msg, Integer id) { + System.out.println("onreturn:" + msg); + ret.put(id, msg); + } + public void onthrow(Throwable ex, Integer id) { + errors.put(id, ex); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/NormalDemoService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/NormalDemoService.java new file mode 100644 index 0000000000..8c89cdb056 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/NormalDemoService.java @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +class NormalDemoService implements IDemoService { + public Person get(int id) { + return new Person(id, "charles`son", 4); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/Person.java b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/Person.java new file mode 100644 index 0000000000..61a366e804 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/callback/implicit/test/Person.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.callback.implicit.test; + +import java.io.Serializable; + +public class Person implements Serializable{ + private static final long serialVersionUID = 1L; + public Person(int id, String name, int age) { + this.id = id; + this.name = name; + this.age = age; + } + private int id; + private String name ; + private int age; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + @Override + public String toString() { + return "Person [name=" + name + ", age=" + age + "]"; + } + } \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/ExceptionTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/ExceptionTest.java new file mode 100644 index 0000000000..42cb94c3eb --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/ExceptionTest.java @@ -0,0 +1,133 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + +import java.util.Date; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ConsumerConfig; +import com.alibaba.dubbo.config.ProviderConfig; +import com.alibaba.dubbo.config.ReferenceConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.util.MyException; +import com.alibaba.dubbo.rpc.util.MyService; +import com.alibaba.dubbo.rpc.util.MyServiceImpl; + +/** + * User: heyman + * Date: 5/18/11 + * Time: 4:20 PM + */ +@SuppressWarnings({"deprecation","rawtypes","unchecked"}) +public class ExceptionTest { + + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + @Test(expected = RuntimeException.class) + public void testException() { + URL url = URL.valueOf("dubbo://127.0.0.1:9010/TestService?codec=dubbo"); + protocol.export(proxy.getInvoker(new MyServiceImpl(), MyService.class, url)); + MyService service = proxy.getProxy(protocol.refer(MyService.class, url)); + try { + service.throwException(); + } catch (MyException e) { + //success + } + service.throwSystemException(); + } + + @Test + public void testMultiClients() { + URL url1 = URL.valueOf("dubbo://127.0.0.1:9010/TestService?codec=dubbo&channels=3"); + URL url2 = URL.valueOf("dubbo://127.0.0.1:9010/TestService2?codec=dubbo&channels=3"); + protocol.export(proxy.getInvoker(new MyServiceImpl(), MyService.class, url1)); + protocol.export(proxy.getInvoker(new MyServiceImpl(), MyService.class, url2)); + MyService service = proxy.getProxy(protocol.refer(MyService.class, url1)); + MyService service2 = proxy.getProxy(protocol.refer(MyService.class, url2)); + service.echo("test"); + /*service.echo("test"); + service.echo("test");*/ + service2.echo("test"); + } + + @Test + public void multiContect() { + + ApplicationConfig application = new ApplicationConfig(); + application.setName("TestServiceServer"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + /*List rcList = new ArrayList(); + rcList.add(registry);*/ + + // 服务提供者全局配置 + ProviderConfig provider = new ProviderConfig(); + provider.setPort(9091); + provider.setThreads(10); + provider.setRegistry(registry); + // provider.setCodec("java"); + //provider.setPayload(32 * 1024 * 1024); // 32m max databuffer + + // 服务提供者暴露服务配置 + ServiceConfig service = new ServiceConfig(); + service.setProvider(provider); // 多个提供者可以用setProviders() + service.setApplication(application); + //service.setRegistry(null); + service.setInterfaceClass(MyService.class); + service.setRef(new MyServiceImpl()); + service.setVersion("1.0.0"); + service.setPath("testService"); + service.export(); // 注意:此调用必需,将触发服务注册。 + + ApplicationConfig applicationc = new ApplicationConfig(); + applicationc.setName("TestServiceServer"); + // 服务消费者全局配置 + ConsumerConfig consumer = new ConsumerConfig(); + consumer.setTimeout(5000); + consumer.setRetries(0); + + // 引用远程服务 + ReferenceConfig reference = new ReferenceConfig(); + //reference.setRegistry(registry); // 多个注册中心可以用setRegistries() + reference.setApplication(application); + reference.setConsumer(consumer); + reference.setInterfaceClass(MyService.class); + reference.setVersion("1.0.0"); + //reference.setMethods(methods); + reference.setTimeout(60 * 1000); //超时60秒 + reference.setCheck(false); + /*Map parameters = new HashMap(); + parameters.put("codec", "hessian2"); + reference.setParameters(parameters);*/ + reference.setUrl("dubbo://127.0.0.1:9091/testService"); + reference.get(); + } + + @Test + public void test() { + System.out.println((new Date()).getTime()); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/ExporterSideConfigUrlTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/ExporterSideConfigUrlTest.java new file mode 100644 index 0000000000..701ec030cf --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/ExporterSideConfigUrlTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + + +/** + * @author haomin.liuhm + * + */ +public class ExporterSideConfigUrlTest extends UrlTestBase { + + private static final Logger log = LoggerFactory.getLogger(ExporterSideConfigUrlTest.class); + + // ====================================================== + // tests start + // ====================================================== + @BeforeClass + public static void start(){ + + + } + + + @Before + public void setUp(){ + + initServConf(); + + return; + } + + @After() + public void teardown() { + } + + @Test + public void exporterMethodConfigUrlTest(){ + + verifyExporterUrlGeneration(methodConfForService, methodConfForServiceTable); + } + + @Test + public void exporterServiceConfigUrlTest(){ + + verifyExporterUrlGeneration(servConf, servConfTable); + } + + @Test + public void exporterProviderConfigUrlTest(){ + + verifyExporterUrlGeneration(provConf, provConfTable); + } + + @Test + public void exporterRegistryConfigUrlTest(){ + + //verifyExporterUrlGeneration(regConfForService, regConfForServiceTable); + } + + + protected void verifyExporterUrlGeneration(T config, Object[][] dataTable) { + + // 1. fill corresponding config with data + //////////////////////////////////////////////////////////// + fillConfigs(config, dataTable, TESTVALUE1); + + // 2. export service and get url parameter string from db + //////////////////////////////////////////////////////////// + servConf.export(); + String paramStringFromDb = getProviderParamString(); + try { + paramStringFromDb = URLDecoder.decode(paramStringFromDb, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // impossible + } + + + assertUrlStringWithLocalTable(paramStringFromDb, dataTable, config.getClass().getName(), TESTVALUE1); + + + // 4. unexport service + //////////////////////////////////////////////////////////// + servConf.unexport(); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/InvokerSideConfigUrlTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/InvokerSideConfigUrlTest.java new file mode 100644 index 0000000000..c450369f5a --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/InvokerSideConfigUrlTest.java @@ -0,0 +1,235 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + +import java.util.Arrays; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ConsumerConfig; +import com.alibaba.dubbo.config.MethodConfig; +import com.alibaba.dubbo.config.ReferenceConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.demo.api.DemoService; + + +/** + * @author haomin.liuhm + * + */ +public class InvokerSideConfigUrlTest extends UrlTestBase { + private static final Logger log = LoggerFactory.getLogger(InvokerSideConfigUrlTest.class); + + // ====================================================== + // invoker related data preparing + // ====================================================== + private ApplicationConfig appConfForConsumer; + private ApplicationConfig appConfForReference; + private RegistryConfig regConfForConsumer; + private RegistryConfig regConfForReference; + private MethodConfig methodConfForReference; + private ConsumerConfig consumerConf; + private ReferenceConfig refConf; + + private Object appConfForConsumerTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + + private Object appConfForReferenceTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + + private Object regConfForConsumerTable[][] = { +// {"timeout", "registry.timeout", "int", 5000, 9000, "", "", "", "", ""}, +// {"file", "registry.file", "string", "", "regConfForServiceTable.log", "", "", "", "", ""}, +// {"wait", "registry.wait", "int", 0, 9000, "", "", "", "", ""}, +// {"transport", "registry.transporter", "string", "netty", "mina", "", "", "", "", ""}, + {"subscribe", "subscribe", "boolean", true, false, "", "", "", "", ""}, + {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""}, + }; + + private Object regConfForReferenceTable[][] = { + {"timeout", "registry.timeout", "int", 5000, 9000, "", "", "", "", ""}, + {"file", "registry.file", "string", "", "regConfForServiceTable.log", "", "", "", "", ""}, + {"wait", "registry.wait", "int", 0, 9000, "", "", "", "", ""}, + {"transport", "registry.transporter", "string", "netty", "mina", "", "", "", "", ""}, + {"subscribe", "subscribe", "boolean", true, false, "", "", "", "", ""}, + {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""}, + }; + + private Object methodConfForReferenceTable[][] = { + {"actives", "eatTiger.actives", "int", 0, 90, "", "", "", "", ""}, + {"executes", "eatTiger.executes", "int", 0, 90, "", "", "", "", ""}, + {"deprecated", "eatTiger.deprecated", "boolean", false, true, "", "", "", "", ""}, + {"async", "eatTiger.async", "boolean", false, true, "", "", "", "", ""}, + {"timeout", "eatTiger.timeout", "int", 0, 90, "", "", "", "", ""}, + }; + + private Object refConfTable[][] = { +// {"version", "version", "string", "0.0.0", "1.2.3", "", "", "", "", ""}, +// {"group", "group", "string", "", "HaominTest", "", "", "", "", ""}, + +// {"delay", "delay", "int", 0, 5, "", "", "", "", ""}, // not boolean + {"timeout", "timeout", "int", 5000, 3000, "", "", "", "", ""}, + {"retries", "retries", "int", 2, 5, "", "", "", "", ""}, + {"connections", "connections", "boolean", 100, 20, "", "", "", "", ""}, + {"loadbalance", "loadbalance", "string", "random", "roundrobin", "leastactive", "", "", ""}, + {"async", "async", "boolean", false, true, "", "", "", "", ""}, + //excluded = true +// {"generic", "generic", "boolean", false, true, "", "", "", "", ""}, + {"check", "check", "boolean", false, true, "", "", "", "", ""}, + //{"local", "local", "string", "false", "HelloServiceLocal", "true", "", "", "", ""}, + //{"local", "local", "string", "false", "true", "", "", "", "", ""}, + //{"mock", "mock", "string", "false", "dubbo.test.HelloServiceMock", "true", "", "", "", ""}, + {"mock", "mock", "string", "false", "false", "", "", "", "", ""}, + {"proxy", "proxy", "boolean", "javassist", "jdk", "", "", "", "", ""}, + {"client", "client", "string", "netty", "mina", "", "", "", "", ""}, + {"client", "client", "string", "netty", "mina", "", "", "", "", ""}, + {"owner", "owner", "string", "", "haomin/ludvik", "", "", "", "", ""}, + {"actives", "actives", "int", 0, 30, "", "", "", "", ""}, + {"cluster", "cluster", "string", "failover", "failfast", "failsafe", "failback", "forking", "", ""}, + //excluded = true +// {"filter", "service.filter", "string", "default", "-generic", "", "", "", "", ""}, + //excluded = true +// {"listener", "exporter.listener", "string", "default", "-deprecated", "", "", "", "", ""}, + //{"", "", "", "", "", "", "", "", "", ""}, + }; + + private Object consumerConfTable[][] = { + {"timeout", "default.timeout", "int", 5000, 8000, "", "", "", "", ""}, + {"retries", "default.retries", "int", 2, 5, "", "", "", "", ""}, + {"loadbalance", "default.loadbalance", "string", "random", "leastactive", "", "", "", "", ""}, + {"async", "default.async", "boolean", false, true, "", "", "", "", ""}, + {"connections", "default.connections", "int", 100, 5, "", "", "", "", ""}, +// {"generic", "generic", "boolean", false, false, "", "", "", "", ""}, + {"check", "check", "boolean", true, false, "", "", "", "", ""}, + {"proxy", "proxy", "string", "javassist", "jdk", "javassist", "", "", "", ""}, + {"owner", "owner", "string", "", "haomin", "", "", "", "", ""}, + {"actives", "default.actives", "int", 0, 5, "", "", "", "", ""}, + {"cluster", "default.cluster", "string", "failover", "forking", "", "", "", "", ""}, + {"filter", "", "string", "", "", "", "", "", "", ""}, + {"listener", "", "string", "", "", "", "", "", "", ""}, +// {"", "", "", "", "", "", "", "", "", ""}, + }; + + // ====================================================== + // test Start + // ====================================================== + + @BeforeClass + public static void start(){ + + //RegistryController.startRegistryIfAbsence(1); + } + + + @Before + public void setUp(){ + + initServConf(); + initRefConf(); + + return; + } + + @After() + public void teardown() { + + //RegistryServer.reloadCache(); + } + + + @Test + public void consumerConfUrlTest(){ + verifyInvokerUrlGeneration(consumerConf, consumerConfTable); + } + + @Test + public void refConfUrlTest(){ + verifyInvokerUrlGeneration(refConf, refConfTable); + } + + @Ignore + @Test //注册中心的参数不会在与consumer的query merge + public void regConfForConsumerUrlTest(){ + + verifyInvokerUrlGeneration(regConfForConsumer, regConfForConsumerTable); + + } + + // ====================================================== + // private helper + // ====================================================== + private void initRefConf(){ + + appConfForConsumer = new ApplicationConfig(); + appConfForReference = new ApplicationConfig(); + regConfForConsumer = new RegistryConfig(); + regConfForReference = new RegistryConfig(); + methodConfForReference = new MethodConfig(); + + refConf = new ReferenceConfig(); + consumerConf = new ConsumerConfig(); + + refConf.setApplication(appConfForReference); + consumerConf.setApplication(appConfForConsumer); + + refConf.setRegistry(regConfForReference); + consumerConf.setRegistry(regConfForConsumer); + + refConf.setConsumer(consumerConf); + + refConf.setMethods(Arrays.asList(new MethodConfig[]{methodConfForReference})); + + methodConfForReference.setName("sayHello"); + regConfForReference.setAddress("127.0.0.1:9090"); + regConfForReference.setProtocol("mockregistry"); + appConfForReference.setName("ConfigTests"); + refConf.setInterface("com.alibaba.dubbo.demo.api.DemoService"); + } + + private void verifyInvokerUrlGeneration(T config, Object[][] dataTable){ + servConf.export(); + + fillConfigs(config, dataTable, TESTVALUE1); + refConf.get(); + + String subScribedUrlStr = getSubscribedUrlString(); + + System.out.println("url string=========:"+subScribedUrlStr); + String configName = config.getClass().getName(); + int column = TESTVALUE1; + + assertUrlStringWithLocalTable(subScribedUrlStr, dataTable, configName, column); + + //重新refer会判断如果已经订阅过,不再重新订阅。 + try { + refConf.destroy(); + } catch (Exception e) { + } + } + + private String getSubscribedUrlString() { + return MockRegistry.getSubscribedUrl().toString(); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockProtocol.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockProtocol.java new file mode 100644 index 0000000000..9d2fdb4798 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockProtocol.java @@ -0,0 +1,84 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * + * @author haomin.liuhm + * + */ +@Extension("mockprotocol") +public class MockProtocol implements Protocol { + + /* (non-Javadoc) + * @see com.alibaba.dubbo.rpc.Protocol#getDefaultPort() + */ + public int getDefaultPort() { + + return 0; + } + + /* (non-Javadoc) + * @see com.alibaba.dubbo.rpc.Protocol#export(com.alibaba.dubbo.rpc.Invoker) + */ + public Exporter export(Invoker invoker) throws RpcException { + return null; + } + + /* (non-Javadoc) + * @see com.alibaba.dubbo.rpc.Protocol#refer(java.lang.Class, com.alibaba.dubbo.common.URL) + */ + public Invoker refer(Class type, URL url) throws RpcException { + + final URL u = url; + + return new Invoker(){ + public Class getInterface(){ + return null; + } + public URL getUrl(){ + return u; + } + public boolean isAvailable(){ + return true; + } + public Result invoke(Invocation invocation) throws RpcException{ + return null; + } + + public void destroy(){ + + } + }; + } + + /* (non-Javadoc) + * @see com.alibaba.dubbo.rpc.Protocol#destroy() + */ + public void destroy() { + + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockRegistry.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockRegistry.java new file mode 100644 index 0000000000..4dfa3c07b2 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockRegistry.java @@ -0,0 +1,101 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.Registry; + +/** + * TODO Comment of MockRegistry + * @author haomin.liuhm + * + */ +public class MockRegistry implements Registry { + + static URL subscribedUrl = new URL("null", "0.0.0.0", 0); + + public static URL getSubscribedUrl(){ + return subscribedUrl; + } + + /* + * @see com.alibaba.dubbo.common.Node#getUrl() + */ + public URL getUrl() { + return null; + } + + /* + * @see com.alibaba.dubbo.common.Node#isAvailable() + */ + public boolean isAvailable() { + return true; + } + + /* + * @see com.alibaba.dubbo.common.Node#destroy() + */ + public void destroy() { + + } + + /* + * @see com.alibaba.dubbo.registry.RegistryService#register(com.alibaba.dubbo.common.URL) + */ + public void register(URL url) { + + } + + /* + * @see com.alibaba.dubbo.registry.RegistryService#unregister(com.alibaba.dubbo.common.URL) + */ + public void unregister(URL url) { + + } + + /* + * @see com.alibaba.dubbo.registry.RegistryService#subscribe(com.alibaba.dubbo.common.URL, com.alibaba.dubbo.registry.NotifyListener) + */ + public void subscribe(URL url, NotifyListener listener) { + this.subscribedUrl = url; + List urls = new ArrayList(); + + urls.add(url.setProtocol("mockprotocol") + .addParameter(Constants.METHODS_KEY, "sayHello")); + + listener.notify(urls); + } + + /* + * @see com.alibaba.dubbo.registry.RegistryService#unsubscribe(com.alibaba.dubbo.common.URL, com.alibaba.dubbo.registry.NotifyListener) + */ + public void unsubscribe(URL url, NotifyListener listener) { + + } + + /* + * @see com.alibaba.dubbo.registry.RegistryService#lookup(com.alibaba.dubbo.common.URL) + */ + public List lookup(URL url) { + return null; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockRegistryFactory.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockRegistryFactory.java new file mode 100644 index 0000000000..9533c30551 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/MockRegistryFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; + +/** + * TODO Comment of MockRegistryFactory + * @author haomin.liuhm + * + */ +@Extension("mockregistry") +public class MockRegistryFactory implements RegistryFactory { + + /* + * @see com.alibaba.dubbo.registry.RegistryFactory#getRegistry(com.alibaba.dubbo.common.URL) + */ + public Registry getRegistry(URL url) { + + return new MockRegistry(); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/UrlTestBase.java b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/UrlTestBase.java new file mode 100644 index 0000000000..70a70be49b --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/config/test/UrlTestBase.java @@ -0,0 +1,218 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.config.test; + + +import java.util.Arrays; + +import org.junit.Assert; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.MethodConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.ProviderConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.provider.impl.DemoServiceImpl; +import com.alibaba.dubbo.rpc.util.RpcConfigGetSetProxy; + +/** + * @author haomin.liuhm + * + */ + +@SuppressWarnings("unused") +public class UrlTestBase { + + private static final Logger log = LoggerFactory.getLogger(UrlTestBase.class); + + // ====================================================== + // data column definition + // ====================================================== + protected static final int KEY = 0; + protected static final int URL_KEY = 1; + private static final int TYPE = 2; + private static final int DEFAULT = 3; + protected static final int TESTVALUE1 = 4; + private static final int TESTVALUE2 = 5; + private static final int TESTVALUE3 = 6; + private static final int TESTVALUE4 = 7; + private static final int TESTVALUE5 = 8; + private static final int TESTVALUE6 = 9; + private static final int TESTVALUE7 = 10; + protected ApplicationConfig appConfForProvider; + protected ApplicationConfig appConfForService; + protected RegistryConfig regConfForProvider; + protected RegistryConfig regConfForService; + protected ProviderConfig provConf; + protected ProtocolConfig protoConfForProvider; + protected ProtocolConfig protoConfForService; + protected MethodConfig methodConfForService; + protected ServiceConfig servConf; + protected Object servConfTable[][] = { + {"proxy", "proxy", "string", "javassist", "jdk", "javassist", "", "", "", ""}, + {"actives", "actives", "int", 0, 90, "", "", "", "", ""}, + {"executes", "executes", "int", 0, 90, "", "", "", "", ""}, + {"deprecated", "deprecated", "boolean", false, true, "", "", "", "", ""}, + {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""}, + {"accesslog", "accesslog", "string", "", "haominTest", "", "", "", "", ""}, + {"document", "document", "string", "", "http://b2b-doc.alibaba-inc.com/display/RC/dubbo_devguide.htm?testquery=你好你好", "", "", "", "", ""}, + {"weight", "weight", "int", 0, 90, "", "", "", "", ""}, + + //{"filter", "service.filter", "string", "", "", "", "", "", "", ""}, + //{"listener", "listener", "string", "", "", "", "", "", "", ""}, + + }; + + private Object appConfForProviderTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + private Object appConfForServiceTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + private Object regConfForProviderTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + protected Object regConfForServiceTable[][] = { + // {"timeout", "registry.timeout", "int", 5000, 9000, "", "", "", "", ""}, + // {"file", "registry.file", "string", "", "regConfForServiceTable.log", "", "", "", "", ""}, + // {"wait", "registry.wait", "int", 0, 9000, "", "", "", "", ""}, + // {"transport", "registry.transporter", "string", "netty", "mina", "", "", "", "", ""}, + // {"subscribe", "subscribe", "boolean", true, false, "", "", "", "", ""}, + {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""}, + }; + private Object protoConfForProviderTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + private Object protoConfForServiceTable[][] = { + {"", "", "", "", "", "", "", "", "", ""}, + }; + protected Object provConfTable[][] = { + {"cluster", "default.cluster", "string", "string", "failover", "failfast", "failsafe", "", "", ""}, + {"async", "default.async", "boolean", false, true, "", "", "", "", ""}, + {"loadbalance", "default.loadbalance", "string", "random", "leastactive", "", "", "", "", ""}, + {"connections", "default.connections", "int", 0, 60, "", "", "", "", ""}, + {"retries", "default.retries", "int", 2, 60, "", "", "", "", ""}, + {"timeout", "default.timeout", "int", 5000, 60, "", "", "", "", ""}, + //change by fengting listener 没有缺省值 + //{"listener", "exporter.listener", "string", "", "", "", "", "", "", ""}, + //{"filter", "service.filter", "string", "", "", "", "", "", "", ""}, + + }; + protected Object methodConfForServiceTable[][] = { + {"actives", "sayHello.actives", "int", 0, 90, "", "", "", "", ""}, + {"executes", "sayHello.executes", "int", 0, 90, "", "", "", "", ""}, + {"deprecated", "sayHello.deprecated", "boolean", false, true, "", "", "", "", ""}, + {"async", "sayHello.async", "boolean", false, true, "", "", "", "", ""}, + {"timeout", "sayHello.timeout", "int", 0, 90, "", "", "", "", ""}, + }; + protected DemoService demoService = new DemoServiceImpl(); + + // ====================================================== + // data table manipulation utils + // ====================================================== + protected String genParamString(Object urlKey, Object value) { + + return (String)urlKey + "=" + value.toString(); + } + + protected void fillConfigs(T conf, Object[][] table, int column) { + + for(Object[] row : table){ + fillConfig(conf, row, column); + } + } + + protected void fillConfig(T conf, Object[] row, int column) { + + RpcConfigGetSetProxy proxy = new RpcConfigGetSetProxy(conf); + proxy.setValue((String)row[KEY], row[column]); + + } + + @SuppressWarnings("deprecation") + protected void initServConf() { + + appConfForProvider = new ApplicationConfig(); + appConfForService = new ApplicationConfig(); + regConfForProvider = new RegistryConfig(); + regConfForService = new RegistryConfig(); + provConf = new ProviderConfig(); + protoConfForProvider = new ProtocolConfig(); + protoConfForService = new ProtocolConfig(); + methodConfForService = new MethodConfig(); + servConf = new ServiceConfig(); + + provConf.setApplication(appConfForProvider); + servConf.setApplication(appConfForService); + + provConf.setRegistry(regConfForProvider); + servConf.setRegistry(regConfForService); + + provConf.setProtocols(Arrays.asList(new ProtocolConfig[]{protoConfForProvider})); + servConf.setProtocols(Arrays.asList(new ProtocolConfig[]{protoConfForService})); + + servConf.setMethods(Arrays.asList(new MethodConfig[]{methodConfForService})); + servConf.setProvider(provConf); + + servConf.setRef(demoService); + servConf.setInterfaceClass(DemoService.class); + + methodConfForService.setName("sayHello"); + regConfForService.setAddress("127.0.0.1:9090"); + regConfForService.setProtocol("mockregistry"); + appConfForService.setName("ConfigTests"); + } + + protected String getProviderParamString() { + return servConf.getExportedUrls().get(0).toString(); + } + + /** + * @param paramStringFromDb + * @param dataTable + * @param configName + * @param column + */ + protected void assertUrlStringWithLocalTable(String paramStringFromDb, + Object[][] dataTable, String configName, int column) { + final String FAILLOG_HEADER = "The following config items are not found in URL: "; + + log.warn("Verifying service url for " + configName + "... "); + log.warn("Consumer url string: " + paramStringFromDb); + + String failLog = FAILLOG_HEADER; + for(Object[] row : dataTable){ + + String targetString = genParamString(row[URL_KEY], row[column]); + + log.warn("Checking " + (String)row[KEY] + "for" + targetString); + if (paramStringFromDb.contains(targetString)){ + log.warn((String)row[KEY] + " --> " + targetString + " OK!"); + } else { + failLog += targetString + ", "; + } + } + + if( !failLog.equals(FAILLOG_HEADER)){ + Assert.fail(failLog); + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Address.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Address.java new file mode 100644 index 0000000000..59d127ceb8 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Address.java @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; + +/** + * Address + * + * @author william.liangf + */ +public class Address implements Serializable { + + private static final long serialVersionUID = 2472090310183915884L; + + private String city; + + private String street; + + private String code; + + public Address() { + } + + public Address(String city, String street, String code) { + this.city = city; + this.street = street; + this.code = code; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + @Override + public String toString() { + return "Address [city=" + city + ", code=" + code + ", street=" + street + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoService.java new file mode 100644 index 0000000000..4ecfe84e63 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoService.java @@ -0,0 +1,81 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * DemoService + * + * @author william.liangf + */ +public interface DemoService extends MapService> { + + List getEnvironment(); + + List getScene(); + + Welcome sayHello(User user); + + String sayOK(); + + void say(); + + String sayName(String name); + + String sayParams(String name, String parentId, Role[] roles); + + long sayLong(long id); + + float sayFloat(float id); + + short sayShort(short id); + + Role sayRole(Role role); + + Role[] sayRoles(Role[] role); + + List sayList(List users); + + Welcome sayTwoHello(User user, User user2); + + String sayTwoName(String name1, String name2); + + HashSet sayTwoParam(String name1, HashSet name2); + + String sayQuery(IndexQueryParameter param); + + Map sayMap(Map map); + + HashMap sayHashMap(HashMap map); + + LinkedHashMap sayLinkedHashMap(LinkedHashMap map); + + void throwException(); + + List listPerson(Person person); + + Person showPerson(Person person); + + void subscribe(IDemoCallback callback,String arg1); + + void unsubscribe(IDemoCallback callback); + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoServiceMock.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoServiceMock.java new file mode 100644 index 0000000000..14ce459734 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoServiceMock.java @@ -0,0 +1,146 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * DemoServiceMock + * + * @author william.liangf + */ +public class DemoServiceMock implements DemoService { + + public Welcome sayHello(User user) { + System.out.println("-------------Mock"); + return null; + } + + public String sayOK() { + return "ERR"; + } + + public void say() { + + } + + public String sayName(String name) { + return null; + } + + public Role sayRole(Role role) { + return null; + } + + public Role[] sayRoles(Role[] role) { + + return null; + } + + public List sayList(List role) { + + return null; + } + + public Welcome sayTwoHello(User user, User user2) { + + return null; + } + + public String sayTwoName(String name1, String name2) { + + return null; + } + + public String sayQuery(IndexQueryParameter param) { + + return null; + } + + public Map sayMap(Map map) { + + return null; + } + + public HashMap sayHashMap(HashMap map) { + + return null; + } + + public LinkedHashMap sayLinkedHashMap(LinkedHashMap map) { + + return null; + } + + public void throwException() { + + } + + public long sayLong(long id) { + + return 0; + } + + public short sayShort(short id) { + + return 0; + } + + public HashSet sayTwoParam(String name1, HashSet name2) { + return null; + } + + public float sayFloat(float id) { + + return 0; + } + + public List getEnvironment() { + + return null; + } + + public List getScene() { + + return null; + } + + public List listPerson(Person person) { + + return null; + } + + public Person showPerson(Person person) { + + return null; + } + + public void subscribe(IDemoCallback callback, String arg1) { + + } + + public void unsubscribe(IDemoCallback callback) { + + } + + public String sayParams(String name, String parentId, Role[] roles) { + return null; + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoServiceStub.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoServiceStub.java new file mode 100644 index 0000000000..08b57f2cd8 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/DemoServiceStub.java @@ -0,0 +1,135 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * DemoServiceMock + * + * @author william.liangf + */ +public class DemoServiceStub implements DemoService { + + private DemoService demoService; + + public DemoServiceStub(DemoService demoService){ + this.demoService = demoService; + } + + public Welcome sayHello(User user) { + System.out.println("-----------------Stub"); + return demoService.sayHello(user); + } + + public String sayOK() { + return demoService.sayOK(); + } + + public void say() { + demoService.say(); + } + + public String sayName(String name) { + return demoService.sayName(name); + } + + public long sayLong(long id) { + return demoService.sayLong(id); + } + + public float sayFloat(float id) { + return demoService.sayFloat(id); + } + + public short sayShort(short id) { + return demoService.sayShort(id); + } + + public Role sayRole(Role role) { + return demoService.sayRole(role); + } + + public Role[] sayRoles(Role[] role) { + return demoService.sayRoles(role); + } + + public List sayList(List role) { + return demoService.sayList(role); + } + + public Welcome sayTwoHello(User user, User user2) { + return demoService.sayTwoHello(user, user2); + } + + public String sayTwoName(String name1, String name2) { + return demoService.sayTwoName(name1, name2); + } + + public HashSet sayTwoParam(String name1, HashSet name2) { + return demoService.sayTwoParam(name1, name2); + } + + public String sayQuery(IndexQueryParameter param) { + return demoService.sayQuery(param); + } + + public Map sayMap(Map map) { + return demoService.sayMap(map); + } + + public HashMap sayHashMap(HashMap map) { + return demoService.sayHashMap(map); + } + + public LinkedHashMap sayLinkedHashMap(LinkedHashMap map) { + return demoService.sayLinkedHashMap(map); + } + + public void throwException() { + demoService.throwException(); + } + + public List getEnvironment() { + return demoService.getEnvironment(); + } + + public List getScene() { + return demoService.getScene(); + } + + public List listPerson(Person person) { + return demoService.listPerson(person); + } + + public Person showPerson(Person person) { + return demoService.showPerson(person); + } + + public void subscribe(IDemoCallback callback,String arg1) { + } + + public void unsubscribe(IDemoCallback callback) { + } + + public String sayParams(String name, String parentId, Role[] roles) { + return null; + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/FullAddress.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/FullAddress.java new file mode 100644 index 0000000000..6fd7251324 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/FullAddress.java @@ -0,0 +1,204 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; + +/** + * @author xk1430 + */ +public class FullAddress implements Serializable { + + private static final long serialVersionUID = 5163979984269419831L; + + private String countryId; + + private String countryName; + + private String provinceName; + + private String cityId; + + private String cityName; + + private String streetAddress; + + private String zipCode; + + public void setCountryId(String countryId) { + this.countryId = countryId; + } + + public void setCountryName(String countryName) { + this.countryName = countryName; + } + + public void setProvinceName(String provinceName) { + this.provinceName = provinceName; + } + + public void setCityId(String cityId) { + this.cityId = cityId; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public void setStreetAddress(String streetAddress) { + this.streetAddress = streetAddress; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } + + public String getCountryId() { + return countryId; + } + + public String getCountryName() { + return countryName; + } + + public String getProvinceName() { + return provinceName; + } + + public String getCityId() { + return cityId; + } + + public String getCityName() { + return cityName; + } + + public String getStreetAddress() { + return streetAddress; + } + + public String getZipCode() { + return zipCode; + } + + public FullAddress() { + } + + public FullAddress(String countryId, String provinceName, String cityId, String streetAddress, + String zipCode) { + this.countryId = countryId; + this.countryName = countryId; + this.provinceName = provinceName; + this.cityId = cityId; + this.cityName = cityId; + this.streetAddress = streetAddress; + this.zipCode = zipCode; + } + + public FullAddress(String countryId, String countryName, String provinceName, String cityId, + String cityName, String streetAddress, String zipCode) { + this.countryId = countryId; + this.countryName = countryName; + this.provinceName = provinceName; + this.cityId = cityId; + this.cityName = cityName; + this.streetAddress = streetAddress; + this.zipCode = zipCode; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((cityId == null) ? 0 : cityId.hashCode()); + result = prime * result + ((cityName == null) ? 0 : cityName.hashCode()); + result = prime * result + ((countryId == null) ? 0 : countryId.hashCode()); + result = prime * result + ((countryName == null) ? 0 : countryName.hashCode()); + result = prime * result + ((provinceName == null) ? 0 : provinceName.hashCode()); + result = prime * result + ((streetAddress == null) ? 0 : streetAddress.hashCode()); + result = prime * result + ((zipCode == null) ? 0 : zipCode.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FullAddress other = (FullAddress) obj; + if (cityId == null) { + if (other.cityId != null) + return false; + } else if (!cityId.equals(other.cityId)) + return false; + if (cityName == null) { + if (other.cityName != null) + return false; + } else if (!cityName.equals(other.cityName)) + return false; + if (countryId == null) { + if (other.countryId != null) + return false; + } else if (!countryId.equals(other.countryId)) + return false; + if (countryName == null) { + if (other.countryName != null) + return false; + } else if (!countryName.equals(other.countryName)) + return false; + if (provinceName == null) { + if (other.provinceName != null) + return false; + } else if (!provinceName.equals(other.provinceName)) + return false; + if (streetAddress == null) { + if (other.streetAddress != null) + return false; + } else if (!streetAddress.equals(other.streetAddress)) + return false; + if (zipCode == null) { + if (other.zipCode != null) + return false; + } else if (!zipCode.equals(other.zipCode)) + return false; + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (countryName != null && countryName.length() > 0) { + sb.append(countryName); + } + if (provinceName != null && provinceName.length() > 0) { + sb.append(" "); + sb.append(provinceName); + } + if (cityName != null && cityName.length() > 0) { + sb.append(" "); + sb.append(cityName); + } + if (streetAddress != null && streetAddress.length() > 0) { + sb.append(" "); + sb.append(streetAddress); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IDemoCallback.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IDemoCallback.java new file mode 100644 index 0000000000..31bed37891 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IDemoCallback.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + + +/** + * @author liuchao + * + */ +public interface IDemoCallback{ + + String onChanged(String msg); + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IWelcome.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IWelcome.java new file mode 100644 index 0000000000..2f60f9b7a5 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IWelcome.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +/** + * IWelcome + * + * @author william.liangf + */ +public interface IWelcome { + + User getUser(); + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IndexQueryParameter.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IndexQueryParameter.java new file mode 100644 index 0000000000..3138963ca0 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/IndexQueryParameter.java @@ -0,0 +1,138 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * IndexQueryParameter + * + * @author william.liangf + */ +public class IndexQueryParameter implements Serializable { + + private static final long serialVersionUID = 5035064961368369616L; + + /** + + * 开始的查询页码 + + */ + + private int pageNo = 1; + + /** + + * 本次操作的最大返回记录数 + + */ + + private int pageSize = 24; + + /** + + * 用户查询参数 + + */ + + private HashMap parameters; + + public static IndexQueryParameter create() { + + return new IndexQueryParameter(); + + } + + public IndexQueryParameter() { + + this(new HashMap()); + + } + + public IndexQueryParameter(HashMap parameters) { + + this.parameters = parameters; + + } + + public int getPageNo() { + + return pageNo; + + } + + public IndexQueryParameter setPageNo(int pageNo) { + + this.pageNo = pageNo; + + if (this.pageNo < 1) { + + this.pageNo = 1; + + } + + return this; + + } + + public int getPageSize() { + + return pageSize; + + } + + public IndexQueryParameter setPageSize(int pageSize) { + + this.pageSize = pageSize; + + if (this.pageSize < 0) { + + this.pageSize = 0; + + } + + return this; + + } + + public HashMap getParameters() { + + return parameters; + + } + + public void setParameters(HashMap parameters) { + + this.parameters = parameters; + + } + + public IndexQueryParameter setParameter(String name, String value) { + + this.parameters.put(name, value); + + return this; + + } + + public int getRecordCount() { + + return this.pageNo * this.pageSize; + + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/MapService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/MapService.java new file mode 100644 index 0000000000..b593d44956 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/MapService.java @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +public interface MapService { + + T sayMap(T map); + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Person.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Person.java new file mode 100644 index 0000000000..84f8c80dc7 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Person.java @@ -0,0 +1,151 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; + +/** + * + * @author tony.chenl + */ +public class Person implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + String personId; + + String loginName; + + PersonStatus status; + + String email; + + String penName; + + PersonInfo infoProfile; + + public Person() { + + } + + public Person(String id) { + this.personId = id; + } + + public String getPersonId() { + return personId; + } + + public void setPersonId(String personId) { + this.personId = personId; + } + + public PersonInfo getInfoProfile() { + return infoProfile; + } + + public void setInfoProfile(PersonInfo infoProfile) { + this.infoProfile = infoProfile; + } + + public void setLoginName(String loginName) { + this.loginName = loginName; + } + + public void setStatus(PersonStatus status) { + this.status = status; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setPenName(String penName) { + this.penName = penName; + } + + public String getEmail() { + return this.email; + } + + public String getLoginName() { + return this.loginName; + } + + public PersonStatus getStatus() { + return this.status; + } + + public String getPenName() { + return penName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((email == null) ? 0 : email.hashCode()); + result = prime * result + ((infoProfile == null) ? 0 : infoProfile.hashCode()); + result = prime * result + ((loginName == null) ? 0 : loginName.hashCode()); + result = prime * result + ((penName == null) ? 0 : penName.hashCode()); + result = prime * result + ((personId == null) ? 0 : personId.hashCode()); + result = prime * result + ((status == null) ? 0 : status.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Person other = (Person) obj; + if (email == null) { + if (other.email != null) + return false; + } else if (!email.equals(other.email)) + return false; + if (infoProfile == null) { + if (other.infoProfile != null) + return false; + } else if (!infoProfile.equals(other.infoProfile)) + return false; + if (loginName == null) { + if (other.loginName != null) + return false; + } else if (!loginName.equals(other.loginName)) + return false; + if (penName == null) { + if (other.penName != null) + return false; + } else if (!penName.equals(other.penName)) + return false; + if (personId == null) { + if (other.personId != null) + return false; + } else if (!personId.equals(other.personId)) + return false; + if (status != other.status) + return false; + return true; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/PersonInfo.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/PersonInfo.java new file mode 100644 index 0000000000..82fdc4a111 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/PersonInfo.java @@ -0,0 +1,201 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; +import java.util.List; + +/** + * + * @author tony.chenl + */ +public class PersonInfo implements Serializable { + private static final long serialVersionUID = 7443011149612231882L; + + List phones; + + Phone fax; + + FullAddress fullAddress; + + String mobileNo; + + String name; + + boolean male; + + boolean female; + + String department; + + String jobTitle; + + String homepageUrl; + + public List getPhones() { + return phones; + } + + public void setPhones(List phones) { + this.phones = phones; + } + + public boolean isMale() { + return male; + } + + public void setMale(boolean male) { + this.male = male; + } + + public boolean isFemale() { + return female; + } + + public void setFemale(boolean female) { + this.female = female; + } + + public void setFax(Phone fax) { + this.fax = fax; + } + + public void setFullAddress(FullAddress fullAddress) { + this.fullAddress = fullAddress; + } + + public void setMobileNo(String mobileNo) { + this.mobileNo = mobileNo; + } + + public void setName(String name) { + this.name = name; + } + + public void setDepartment(String department) { + this.department = department; + } + + public void setJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + } + + public void setHomepageUrl(String homepageUrl) { + this.homepageUrl = homepageUrl; + } + + public String getDepartment() { + return department; + } + + public Phone getFax() { + return fax; + } + + public FullAddress getFullAddress() { + return fullAddress; + } + + public String getHomepageUrl() { + return homepageUrl; + } + + public String getJobTitle() { + return jobTitle; + } + + public String getMobileNo() { + return mobileNo; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((department == null) ? 0 : department.hashCode()); + result = prime * result + ((fax == null) ? 0 : fax.hashCode()); + result = prime * result + (female ? 1231 : 1237); + result = prime * result + ((fullAddress == null) ? 0 : fullAddress.hashCode()); + result = prime * result + ((homepageUrl == null) ? 0 : homepageUrl.hashCode()); + result = prime * result + ((jobTitle == null) ? 0 : jobTitle.hashCode()); + result = prime * result + (male ? 1231 : 1237); + result = prime * result + ((mobileNo == null) ? 0 : mobileNo.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((phones == null) ? 0 : phones.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PersonInfo other = (PersonInfo) obj; + if (department == null) { + if (other.department != null) + return false; + } else if (!department.equals(other.department)) + return false; + if (fax == null) { + if (other.fax != null) + return false; + } else if (!fax.equals(other.fax)) + return false; + if (female != other.female) + return false; + if (fullAddress == null) { + if (other.fullAddress != null) + return false; + } else if (!fullAddress.equals(other.fullAddress)) + return false; + if (homepageUrl == null) { + if (other.homepageUrl != null) + return false; + } else if (!homepageUrl.equals(other.homepageUrl)) + return false; + if (jobTitle == null) { + if (other.jobTitle != null) + return false; + } else if (!jobTitle.equals(other.jobTitle)) + return false; + if (male != other.male) + return false; + if (mobileNo == null) { + if (other.mobileNo != null) + return false; + } else if (!mobileNo.equals(other.mobileNo)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (phones == null) { + if (other.phones != null) + return false; + } else if (!phones.equals(other.phones)) + return false; + return true; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/PersonStatus.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/PersonStatus.java new file mode 100644 index 0000000000..f6014e5567 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/PersonStatus.java @@ -0,0 +1,25 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +/** + * + * @author tony.chenl + */ +public enum PersonStatus { + ENABLED, + DISABLED +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Phone.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Phone.java new file mode 100644 index 0000000000..b6f31e7c33 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Phone.java @@ -0,0 +1,143 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; + +/** + * 电话号码 + * + * @author xk1430 + */ +public class Phone implements Serializable { + + private static final long serialVersionUID = 4399060521859707703L; + + private String country; + + private String area; + + private String number; + + private String extensionNumber; + + public Phone() { + } + + public Phone(String country, String area, String number, String extensionNumber) { + this.country = country; + this.area = area; + this.number = number; + this.extensionNumber = extensionNumber; + } + + public void setCountry(String country) { + this.country = country; + } + + public void setArea(String area) { + this.area = area; + } + + public void setNumber(String number) { + this.number = number; + } + + public void setExtensionNumber(String extensionNumber) { + this.extensionNumber = extensionNumber; + } + + public String getCountry() { + return country; + } + + public String getArea() { + return area; + } + + public String getNumber() { + return number; + } + + public String getExtensionNumber() { + return extensionNumber; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((area == null) ? 0 : area.hashCode()); + result = prime * result + ((country == null) ? 0 : country.hashCode()); + result = prime * result + ((extensionNumber == null) ? 0 : extensionNumber.hashCode()); + result = prime * result + ((number == null) ? 0 : number.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Phone other = (Phone) obj; + if (area == null) { + if (other.area != null) + return false; + } else if (!area.equals(other.area)) + return false; + if (country == null) { + if (other.country != null) + return false; + } else if (!country.equals(other.country)) + return false; + if (extensionNumber == null) { + if (other.extensionNumber != null) + return false; + } else if (!extensionNumber.equals(other.extensionNumber)) + return false; + if (number == null) { + if (other.number != null) + return false; + } else if (!number.equals(other.number)) + return false; + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (country != null && country.length() > 0) { + sb.append(country); + sb.append("-"); + } + if (area != null && area.length() > 0) { + sb.append(area); + sb.append("-"); + } + if (number != null && number.length() > 0) { + sb.append(number); + } + if (extensionNumber != null && extensionNumber.length() > 0) { + sb.append("-"); + sb.append(extensionNumber); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Role.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Role.java new file mode 100644 index 0000000000..12f151e496 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Role.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +/** + * Role + * + * @author william.liangf + */ +public enum Role { + + GUEST, MEMBER, ADMINISTRATOR + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/User.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/User.java new file mode 100644 index 0000000000..04b7cab8ed --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/User.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * User + * + * @author william.liangf + */ +public class User implements Serializable { + + private static final long serialVersionUID = 5840134024756337246L; + + private String name; + + private int age; + + private String[] phones; + + private Address address; + + private Role role; + + public User() { + } + + public User(String name, int age, String[] phones, Address address, Role role) { + super(); + this.name = name; + this.age = age; + this.phones = phones; + this.address = address; + this.role = role; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String[] getPhones() { + return phones; + } + + public void setPhones(String[] phones) { + this.phones = phones; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } + + @Override + public String toString() { + return "User [address=" + address + ", age=" + age + ", name=" + name + ", phones=" + + Arrays.toString(phones) + "]" + ", role=" + + role + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Welcome.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Welcome.java new file mode 100644 index 0000000000..e20023c084 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/api/Welcome.java @@ -0,0 +1,80 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.api; + +import java.io.Serializable; + +/** + * Hello + * + * @author william.liangf + */ +public class Welcome implements IWelcome, Serializable { + + private static final long serialVersionUID = 1L; + + private String salutatory; + + private User user; + + private User user2; + + public Welcome() { + } + + public Welcome(String salutatory, User user) { + super(); + this.salutatory = salutatory; + this.user = user; + } + + public Welcome(String salutatory, User user, User user2) { + super(); + this.salutatory = salutatory; + this.user = user; + this.user2 = user2; + } + + public String getSalutatory() { + return salutatory; + } + + public void setSalutatory(String salutatory) { + this.salutatory = salutatory; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public User getUser2() { + return user2; + } + + public void setUser2(User user2) { + this.user2 = user2; + } + + @Override + public String toString() { + return "Welcome [salutatory=" + salutatory + ", user=" + user + ", user2=" + user2 + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/CodeConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/CodeConsumer.java new file mode 100644 index 0000000000..3335f4c1a5 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/CodeConsumer.java @@ -0,0 +1,75 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ReferenceConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.demo.api.Address; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * CodeProvider + * + * @author william.liangf + */ +public class CodeConsumer { + + @SuppressWarnings("deprecation") + public static void main(String[] args) throws Exception { + ApplicationConfig application = new ApplicationConfig(); + application.setName("code-consumer"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("10.20.153.28:9090"); + registry.setUsername("admin"); + registry.setPassword("hello1234"); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(application); + reference.setRegistry(registry); + reference.setInterfaceClass(DemoService.class); + reference.setVersion("1.0.0"); + DemoService demoService = reference.get(); + + User user = new User("liangfei", 25, new String[]{"13012345678", "1308654321"}, new Address("hangzhou", "wangshang", "310052"), Role.MEMBER); + for (int i = 0; i < 1; i ++) { + try { + RpcContext.getContext().setAttachment("i", String.valueOf(i)); + Welcome result = demoService.sayHello(user); + System.out.println("-------- (" + i + ") " + result); + } catch (Exception e) { + e.printStackTrace(); + } + } + + reference.destroy(); + + synchronized (CodeConsumer.class) { + while (true) { + try { + CodeConsumer.class.wait(); + } catch (InterruptedException e) { + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/ComplexConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/ComplexConsumer.java new file mode 100644 index 0000000000..994981e7f4 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/ComplexConsumer.java @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.demo.api.Address; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; + +/** + * SimpleConsumer + * + * @author william.liangf + */ +public class ComplexConsumer { + + public static void main(String[] args) throws Throwable { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:complex_consumer.xml"); + context.start(); + DemoService demoService = (DemoService)context.getBean("demoService"); + User user = new User("liangfei", 25, new String[]{"13012345678", "1308654321"}, new Address("hangzhou", "wangshang", "310052"), Role.MEMBER); + List users = new ArrayList(); + users.add(user); + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + Thread.sleep(2000); + try { + long start = System.currentTimeMillis(); + Welcome result = demoService.sayHello(user); + List us = demoService.sayList(users); + User u = us.get(0); + System.out.println("--------elapsed: " + (System.currentTimeMillis() - start) + "ms, result: " + result + ", list: " + u); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/DemoCallBackImpl.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/DemoCallBackImpl.java new file mode 100644 index 0000000000..00d072be03 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/DemoCallBackImpl.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import com.alibaba.dubbo.demo.api.IDemoCallback; + + +/** + * @author chao.liuc + * + */ +public class DemoCallBackImpl implements IDemoCallback{ + public String onChanged(String msg) { + System.out.println("Recived callback: " + msg); + return "onChanged"; + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/DirectConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/DirectConsumer.java new file mode 100644 index 0000000000..35b6c4a7a9 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/DirectConsumer.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.demo.api.Address; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * DirectConsumer + * + * @author william.liangf + */ +public class DirectConsumer { + + public static void main(String[] args) throws Throwable { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:direct_consumer.xml"); + context.start(); + DemoService demoService = (DemoService)context.getBean("demoService"); + User user = new User("liangfei", 25, new String[]{"13012345678", "1308654321"}, new Address("hangzhou", "wangshang", "310052"), Role.MEMBER); + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + Thread.sleep(2000); + try { + RpcContext.getContext().setAttachment("i", String.valueOf(i)); + Welcome result = demoService.sayHello(user); + System.out.println("-------- (" + i + ") " + result); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/GenericConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/GenericConsumer.java new file mode 100644 index 0000000000..2b4fcc2a05 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/GenericConsumer.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.rpc.service.GenericService; + +public class GenericConsumer { + + public static void main(String[] args) throws Throwable { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:generic_consumer.xml"); + context.start(); + GenericService service = (GenericService)context.getBean("demoService"); + Map address = new HashMap(); + address.put("class", "com.alibaba.dubbo.demo.api.Address"); + address.put("city", "hangzhou"); + address.put("street", "wangshang"); + address.put("code", "310052"); + Map user = new HashMap(); + user.put("class", "com.alibaba.dubbo.demo.api.User"); + user.put("name", "liangfei"); + user.put("age", 25); + user.put("role", "MEMBER"); + user.put("address", address); + user.put("phones", new String[]{"13012345678", "1308654321"}); + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + Thread.sleep(2000); + try { + Object result = service.$invoke("sayHello", new String[]{"com.alibaba.dubbo.demo.api.User"}, new Object[]{user}); + System.out.println("-------- (" + i + ") " + result); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/InjvmConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/InjvmConsumer.java new file mode 100644 index 0000000000..6992395df6 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/InjvmConsumer.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.demo.api.Address; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * SimpleConsumer + * + * @author william.liangf + */ +public class InjvmConsumer { + + public static void main(String[] args) throws Throwable { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:injvm_consumer.xml"); + context.start(); + DemoService demoService = (DemoService)context.getBean("demoService"); + User user = new User("liangfei", 25, new String[]{"13012345678", "1308654321"}, new Address("hangzhou", "wangshang", "310052"), Role.MEMBER); + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + Thread.sleep(2000); + try { + RpcContext.getContext().setAttachment("i", String.valueOf(i)); + Welcome result = demoService.sayHello(user); + System.out.println("-------- (" + i + ") " + result); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/PerformanceConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/PerformanceConsumer.java new file mode 100644 index 0000000000..02d800946b --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/PerformanceConsumer.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.demo.api.Address; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * SimpleConsumer + * + * @author william.liangf + */ +public class PerformanceConsumer { + + public static void main(String[] args) throws Throwable { + final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:performance_consumer.xml"); + context.start(); + final DemoService demoService = (DemoService)context.getBean("demoService"); + final User user = new User("liangfei", 25, new String[]{"13012345678", "1308654321"}, new Address("hangzhou", "wangshang", "310052"), Role.MEMBER); + final AtomicInteger count = new AtomicInteger(); + final AtomicInteger error = new AtomicInteger(); + for (int n = 0; n < 11; n ++) { + new Thread(new Runnable() { + public void run() { + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + try { + int c = count.incrementAndGet(); + if (c % 100 == 0) { + System.out.println("count: " + count.get() + ", error: " + error.get()); + } + RpcContext.getContext().setAttachment("i", String.valueOf(i)); + Welcome result = demoService.sayHello(user); + // System.out.println(result); + User user = result.getUser(); + if (! "liangfei".equals(user.getName())) { + throw new IllegalStateException("Invalid result " + user.getName()); + } + } catch (Exception e) { + error.incrementAndGet(); + //if (e.getMessage().contains("ExecutionException")) { + e.printStackTrace(); + //} + System.out.println("count: " + count.get() + ", error: " + error.get()); + } + } + } + }).start(); + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/SimpleConsumer.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/SimpleConsumer.java new file mode 100644 index 0000000000..76240b1bc0 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/consumer/SimpleConsumer.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.consumer; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.demo.api.Address; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * SimpleConsumer + * + * @author william.liangf + */ +public class SimpleConsumer { + + public static void main(String[] args) throws Throwable { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:simple_consumer.xml"); + context.start(); + DemoService demoService = (DemoService)context.getBean("demoService"); + User user = new User("liang\nfei", 25, new String[]{"13012345678", "1308654321"}, new Address("hangzhou", "wangshang", "310052"), Role.MEMBER); + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + try { + RpcContext.getContext().setAttachment("i", String.valueOf(i)); + Welcome result = demoService.sayHello(user); + System.out.println("-------- (" + i + ") " + result); + } catch (Exception e) { + e.printStackTrace(); + } + Thread.sleep(3000); + } + synchronized (SimpleConsumer.class) { + SimpleConsumer.class.wait(); + } + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/monitor/SimpleMonitor.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/monitor/SimpleMonitor.java new file mode 100644 index 0000000000..23f92106de --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/monitor/SimpleMonitor.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.monitor; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * SimpleMonitor + * + * @author william.liangf + */ +public class SimpleMonitor { + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:simple_monitor.xml"); + context.start(); + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/CodeProvider.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/CodeProvider.java new file mode 100644 index 0000000000..6817139dc0 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/CodeProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider; + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.provider.impl.DemoServiceImpl; + +/** + * CodeProvider + * + * @author william.liangf + */ +public class CodeProvider { + + @SuppressWarnings("deprecation") + public static void main(String[] args) throws Exception { + DemoService demoService = new DemoServiceImpl(); + + ApplicationConfig application = new ApplicationConfig(); + application.setName("code-provider"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("10.20.153.28:9090"); + registry.setUsername("admin"); + registry.setPassword("hello1234"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(20883); + + ServiceConfig service = new ServiceConfig(); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.setInterfaceClass(DemoService.class); + service.setVersion("1.0.0"); + service.setRef(demoService); + service.export(); + + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/ComplexProvider.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/ComplexProvider.java new file mode 100644 index 0000000000..ad4ad4aa87 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/ComplexProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * ComplexProvider + * + * @author william.liangf + */ +public class ComplexProvider { + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:complex_provider.xml"); + context.start(); + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/DirectProvider.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/DirectProvider.java new file mode 100644 index 0000000000..7c5c10dbf5 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/DirectProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * SimpleProvider + * + * @author william.liangf + */ +public class DirectProvider { + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:direct_provider.xml"); + context.start(); + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/GenericProvider.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/GenericProvider.java new file mode 100644 index 0000000000..43e2dbb0e6 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/GenericProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * GenericProvider + * + * @author william.liangf + */ +public class GenericProvider { + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:generic_provider.xml"); + context.start(); + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/SimpleProvider.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/SimpleProvider.java new file mode 100644 index 0000000000..44a6b3f90d --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/SimpleProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * SimpleProvider + * + * @author william.liangf + */ +public class SimpleProvider { + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:simple_provider.xml"); + context.start(); + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceGenericImpl.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceGenericImpl.java new file mode 100644 index 0000000000..92e9c66f73 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceGenericImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider.impl; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.service.GenericException; +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * DemoServiceGenericeImpl + * + * @author william.liangf + */ +public class DemoServiceGenericImpl implements GenericService { + + public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { + if ("sayHello".equals(method)) { + System.out.println(">>>>>>DemoServiceGenericImpl: " + args[0]); + Map map = new HashMap(); + map.put("salutatory", "generic provider: " + RpcContext.getContext().getLocalAddress()); + map.put("user", args[0]); + return map; + } + return null; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceImpl.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceImpl.java new file mode 100644 index 0000000000..bd6aed7444 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceImpl.java @@ -0,0 +1,192 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.IDemoCallback; +import com.alibaba.dubbo.demo.api.IndexQueryParameter; +import com.alibaba.dubbo.demo.api.Person; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.performance.PerformanceUtils; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * DemoServiceImpl + * + * @author william.liangf + */ +public class DemoServiceImpl implements DemoService { + + public Welcome sayHello(User user) { +// throw new RuntimeException(); + System.out.println("(" + RpcContext.getContext().getAttachment("i") + + ") >>>>>>DemoServiceImpl: " + user); + return new Welcome("provider: " + RpcContext.getContext().getLocalAddress(), user); + } + + public void say() { + System.out.println(">>>>>>>>>>>>>>>>>>>say()"); + } + + public String sayOK() { + return "OK"; + } + + public String sayName(String name) { + return "say:" + name; + } + + public Welcome sayTwoHello(User user, User user2) { + return new Welcome("Hello", user, user2); + } + + public String sayTwoName(String name1, String name2) { + return name1 + " and " + name2; + } + + public String sayQuery(IndexQueryParameter param) { + return param.getParameters().toString(); + } + + public Role sayRole(Role role) { + return role; + } + + public Role[] sayRoles(Role[] roles) { + return roles; + } + + public Map sayMap(Map map) { + map.put("xx", "yy"); + return map; + } + + public void throwException() { + throw new RuntimeException("OK"); + } + + public LinkedHashMap sayLinkedHashMap(LinkedHashMap map) { + return map; + } + + public HashMap sayHashMap(HashMap map) { + return map; + } + + public long sayLong(long id) { + return id; + } + + public short sayShort(short id) { + return id; + } + + public List sayList(List roles) { + return roles; + } + + public HashSet sayTwoParam(String name1, HashSet name2) { + name2.add(name1); + return name2; + } + + public float sayFloat(float id) { + return id; + } + + public List getEnvironment() { + return PerformanceUtils.getEnvironment(); + } + + public List getScene() { + return PerformanceUtils.getScene(); + } + + public List listPerson(Person person) { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + list.add(person); + } + return list; + } + + public Person showPerson(Person person) { + return person; + } + + private volatile Thread t; + private Vector callbacks = new Vector(); + + public void subscribe(final IDemoCallback callback, final String arg1) { + System.out.println("+++subscribe callback id is:" + System.identityHashCode(callback) +arg1); +// callback.onChanged("This is callback data."); + synchronized (callbacks) { + if(!callbacks.contains(callback)) + callbacks.add(callback); + } + if (t == null) { + t = new Thread(new Runnable() { + public void run() { + for (int i = 0; i < 1000; i++) { + Vector callbacks2 = new Vector(callbacks); + Iterator iter = callbacks2.iterator(); + while(iter != null && iter.hasNext()){ + //有并发修改问题. + IDemoCallback callback = iter.next(); + long time = System.currentTimeMillis(); + System.out.print(" server request id: "+time); + String ret = callback.onChanged("server request id:"+ time); + System.out.println(",client callback :" + ret); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + } + }); + t.start(); + } + + System.out.println("+++server side subscribe ok"); + } + + public void unsubscribe(final IDemoCallback callback) { + synchronized (callbacks) { + int size = callbacks.size(); + callbacks.remove(callback); + System.out.println("---unsubscribe callback id is:" + System.identityHashCode(callback)+",callback list size("+size+"->"+callbacks.size()+")"); + } + } + + public String sayParams(String name, String parentId, Role[] roles) { + return "Name:" + name + ", ParentId: " + parentId + ", Roles: " + Arrays.toString(roles); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceImpl2.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceImpl2.java new file mode 100644 index 0000000000..870f6671e7 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/provider/impl/DemoServiceImpl2.java @@ -0,0 +1,162 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.provider.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.IDemoCallback; +import com.alibaba.dubbo.demo.api.IndexQueryParameter; +import com.alibaba.dubbo.demo.api.Person; +import com.alibaba.dubbo.demo.api.Role; +import com.alibaba.dubbo.demo.api.User; +import com.alibaba.dubbo.demo.api.Welcome; +import com.alibaba.dubbo.performance.PerformanceUtils; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * DemoServiceImpl + * + * @author william.liangf + */ +public class DemoServiceImpl2 implements DemoService { + + public Welcome sayHello(User user) { + System.out.println(">>>>>>DemoServiceImpl2: " + user); + return new Welcome("provider2: " + RpcContext.getContext().getLocalAddress(), user); + } + + public void say() { + System.out.println(">>>>>>>>>>>>>>>>>>>say()"); + } + + public String sayOK() { + return "OK"; + } + + public String sayName(String name) { + return "say:" + name; + } + + + public Welcome sayTwoHello(User user, User user2) { + return new Welcome("Hello", user, user2); + } + + + public String sayTwoName(String name1, String name2) { + return name1 + " and " + name2; + } + + + public String sayQuery(IndexQueryParameter param) { + return param.getParameters().toString(); + } + + + public Role sayRole(Role role) { + return role; + } + + + + public Role[] sayRoles(Role[] roles) { + return roles; + } + + + public Map sayMap(Map map) { + map.put("xx", "yy"); + return map; + } + + + public void throwException() { + throw new RuntimeException("OK"); + } + + + public LinkedHashMap sayLinkedHashMap( + LinkedHashMap map) { + return map; + } + + + public HashMap sayHashMap(HashMap map) { + return map; + } + + + public long sayLong(long id) { + return id; + } + + + public short sayShort(short id) { + return id; + } + + + public List sayList(List roles) { + return roles; + } + + + public HashSet sayTwoParam(String name1, HashSet name2) { + name2.add(name1); + return name2; + } + + public float sayFloat(float id) { + return id; + } + + public List getEnvironment() { + return PerformanceUtils.getEnvironment(); + } + + public List getScene() { + return PerformanceUtils.getScene(); + } + + public List listPerson(Person person) { + List list = new ArrayList(); + for (int i = 0; i < 10; i ++) { + list.add(person); + } + return list; + } + + public Person showPerson(Person person) { + return person; + } + + public void subscribe(IDemoCallback callback,String arg1) { + } + + public void unsubscribe(IDemoCallback callback) { + } + + public String sayParams(String name, String parentId, Role[] roles) { + return "Name:" + name + ", ParentId: " + parentId + ", Roles: " + Arrays.toString(roles); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/registry/RegistryServiceLocal.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/registry/RegistryServiceLocal.java new file mode 100644 index 0000000000..6a3d8c98c7 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/registry/RegistryServiceLocal.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.registry; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.RegistryService; + +public class RegistryServiceLocal implements RegistryService { + RegistryService registryService; + ConcurrentMap listeners = new ConcurrentHashMap(); + + + public RegistryServiceLocal(RegistryService registryService) { + this.registryService = registryService; + } + + public void register(URL url) { + registryService.register(url); + } + + public void unregister(URL url) { + registryService.unregister(url); + } + + public void subscribe(URL url, NotifyListener listener) { + registryService.subscribe(url, listener); + listeners.put(url, listener); + } + + public void unsubscribe(URL url, NotifyListener listener) { + registryService.unsubscribe(url, listener); + } + + public List lookup(URL url) { + return registryService.lookup(url); + } + + public void ondisconnect(){ + for(URL url : listeners.keySet()){ + registryService.subscribe(url, listeners.get(url)); + } + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/demo/registry/SimpleRegistry.java b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/registry/SimpleRegistry.java new file mode 100644 index 0000000000..a8eaea2e81 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/demo/registry/SimpleRegistry.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.demo.registry; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +/** + * TODO Comment of SimpleRegistry + * @author william.liangf + * + */ +public class SimpleRegistry { + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:simple_registry.xml"); + context.start(); + System.in.read(); // 输入任意键退出 + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceConsumerTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceConsumerTest.java new file mode 100644 index 0000000000..1be19f9e9a --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceConsumerTest.java @@ -0,0 +1,262 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.performance; + +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ReferenceConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.api.FullAddress; +import com.alibaba.dubbo.demo.api.Person; +import com.alibaba.dubbo.demo.api.PersonInfo; +import com.alibaba.dubbo.demo.api.PersonStatus; +import com.alibaba.dubbo.demo.api.Phone; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; + +/** + * PerformanceClientTest + * + * mvn clean test -Dtest=*PerformanceConsumerTest -Dserver=10.20.153.187:9911 + * + * @author william.liangf + */ +public class PerformanceConsumerTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceConsumerTest.class); + + @SuppressWarnings("deprecation") + @Test + public void testClient() throws Throwable { + // 读取参数 + if (PerformanceUtils.getProperty("server", null) == null) { + logger.warn("Please set -Dserver=127.0.0.1:9911"); + return; + } + final String server = System.getProperty("server", "127.0.0.1:9911"); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final int timeout = PerformanceUtils.getIntProperty(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + final int length = PerformanceUtils.getIntProperty("length", 1024); + final int connections = PerformanceUtils.getIntProperty(Constants.CONNECTIONS_KEY, 1); + final int concurrent = PerformanceUtils.getIntProperty("concurrent", 100); + int r = PerformanceUtils.getIntProperty("runs", 1000); + final int runs = r > 0 ? r : Integer.MAX_VALUE; + final String onerror = PerformanceUtils.getProperty("onerror", "continue"); + + ApplicationConfig application = new ApplicationConfig(); + application.setName("code-consumer"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress(RegistryConfig.NO_AVAILABLE); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(application); + reference.setRegistry(registry); + reference.setInterfaceClass(DemoService.class); + reference.setVersion("1.0.0"); + reference.setConnections(connections); + reference.setTimeout(timeout); + reference.setClient(transporter); + reference.setUrl("dubbo://" + server + "/" + DemoService.class.getName()); + final DemoService demoService = reference.get(); + + List serverEnvironment = demoService.getEnvironment(); + List serverScene = demoService.getScene(); + + // 制造数据 + StringBuilder buf = new StringBuilder(length); + for (int i = 0; i < length; i ++) { + buf.append("A"); + } + final String data = buf.toString(); + + Person person = new Person(); + person.setPersonId("superman111"); + person.setLoginName("superman"); + person.setEmail("sm@1.com"); + person.setPenName("pname"); + person.setStatus(PersonStatus.ENABLED); + + ArrayList phones = new ArrayList(); + Phone phone1 = new Phone("86", "0571", "87654321", "001"); + Phone phone2 = new Phone("86", "0571", "87654322", "002"); + phones.add(phone1); + phones.add(phone2); + PersonInfo pi = new PersonInfo(); + pi.setPhones(phones); + Phone fax = new Phone("86", "0571", "87654321", null); + pi.setFax(fax); + FullAddress addr = new FullAddress("CN", "zj", "3480", "wensanlu", "315000"); + pi.setFullAddress(addr); + pi.setMobileNo("13584652131"); + pi.setMale(true); + pi.setDepartment("b2b"); + pi.setHomepageUrl("www.capcom.com"); + pi.setJobTitle("qa"); + pi.setName("superman"); + person.setInfoProfile(pi); + + // 计数器 + final AtomicLong count = new AtomicLong(); + final AtomicLong error = new AtomicLong(); + final AtomicLong time = new AtomicLong(); + final AtomicLong all = new AtomicLong(); + + // 并发调用 + final CountDownLatch latch = new CountDownLatch(concurrent); + for (int i = 0; i < concurrent; i ++) { + new Thread(new Runnable() { + public void run() { + try { + long init = System.currentTimeMillis(); + for (int i = 0; i < runs; i++) { + try { + count.incrementAndGet(); + long start = System.currentTimeMillis(); + String result = demoService.sayName(data); + long end = System.currentTimeMillis(); + if (! result.endsWith(data)) { + throw new IllegalStateException("Invalid result " + result); + } + time.addAndGet(end - start); + } catch (Exception e) { + error.incrementAndGet(); + e.printStackTrace(); + if ("exit".equals(onerror)) { + System.exit(-1); + } else if ("break".equals(onerror)) { + break; + } else if ("sleep".equals(onerror)) { + try { + Thread.sleep(30000); + } catch (InterruptedException e1) { + } + } + } + } + all.addAndGet(System.currentTimeMillis() - init); + } finally { + latch.countDown(); + } + } + }).start(); + } + + // 输出,tps不精确,但大概反映情况 + new Thread(new Runnable() { + public void run() { + try{ + SimpleDateFormat dateFormat = new SimpleDateFormat ("HH:mm:ss"); + long lastCount = count.get(); + long sleepTime = 2000; + long elapsd = sleepTime/1000; + boolean bfirst = true; + while (latch.getCount() > 0) { + long c = count.get()-lastCount ; + if(! bfirst)//第一次不准 + System.out.println("["+dateFormat.format(new Date()) +"] count: " + count.get() + ", error: " + error.get() + ",tps:"+(c/elapsd)); + + bfirst = false; + lastCount = count.get(); + Thread.sleep(sleepTime); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + }).start(); + + latch.await(); + + long total = count.get(); + long failed = error.get(); + long succeeded = total - failed; + long elapsed = time.get(); + long allElapsed = all.get(); + long clientElapsed = allElapsed - elapsed; + long art = 0; + long qps = 0; + long throughput = 0; + if (elapsed > 0) { + art = elapsed / succeeded; + qps = concurrent * succeeded * 1000 / elapsed; + throughput = concurrent * succeeded * length * 2 * 1000 / elapsed; + } + + PerformanceUtils.printBorder(); + PerformanceUtils.printHeader("Dubbo Remoting Performance Test Report"); + PerformanceUtils.printBorder(); + PerformanceUtils.printHeader("Test Environment"); + PerformanceUtils.printSeparator(); + for (String item: serverEnvironment) { + PerformanceUtils.printBody("Server " + item); + } + PerformanceUtils.printSeparator(); + List clientEnvironment = PerformanceUtils.getEnvironment(); + for (String item: clientEnvironment) { + PerformanceUtils.printBody("Client " + item); + } + PerformanceUtils.printSeparator(); + PerformanceUtils.printHeader("Test Scene"); + PerformanceUtils.printSeparator(); + for (String item: serverScene) { + PerformanceUtils.printBody("Server " + item); + } + PerformanceUtils.printBody("Client Transporter: " + transporter); + PerformanceUtils.printBody("Response Timeout: " + timeout + " ms"); + PerformanceUtils.printBody("Data Length: " + length + " bytes"); + PerformanceUtils.printBody("Client Shared Connections: " + connections); + PerformanceUtils.printBody("Client Concurrent Threads: " + concurrent); + PerformanceUtils.printBody("Run Times Per Thread: " + runs); + PerformanceUtils.printSeparator(); + PerformanceUtils.printHeader("Test Result"); + PerformanceUtils.printSeparator(); + PerformanceUtils.printBody("Succeeded Requests: " + DecimalFormat.getIntegerInstance().format(succeeded)); + PerformanceUtils.printBody("Failed Requests: " + failed); + PerformanceUtils.printBody("Client Elapsed Time: " + clientElapsed + " ms"); + PerformanceUtils.printBody("Average Response Time: " + art + " ms"); + PerformanceUtils.printBody("Requests Per Second: " + qps + "/s"); + PerformanceUtils.printBody("Throughput Per Second: " + DecimalFormat.getIntegerInstance().format(throughput) + " bytes/s"); + PerformanceUtils.printBorder(); + } + + static class PeformanceTestHandler extends ExchangeHandlerAdapter{ + + public void connected(Channel channel) throws RemotingException { + System.out.println("connected event,chanel;"+channel); + } + + public void disconnected(Channel channel) throws RemotingException { + System.out.println("disconnected event,chanel;"+channel); + } + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceProviderTest.java b/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceProviderTest.java new file mode 100644 index 0000000000..98239a25bb --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceProviderTest.java @@ -0,0 +1,187 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.performance; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; +import com.alibaba.dubbo.demo.api.DemoService; +import com.alibaba.dubbo.demo.provider.impl.DemoServiceImpl; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; +import com.alibaba.dubbo.rpc.Protocol; + +/** + * PerformanceServer + * + * mvn clean test -Dtest=*PerformanceProviderTest -Dport=9911 + * + * @author william.liangf + */ +public class PerformanceProviderTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceProviderTest.class); + + private static ServiceConfig service = null; + + @Test + public void testServer() throws Exception { + // 读取参数 + if (PerformanceUtils.getProperty("port", null) == null) { + logger.warn("Please set -Dport=9911"); + return; + } + final int port = PerformanceUtils.getIntProperty("port", 9911); + final boolean telnet = PerformanceUtils.getBooleanProperty("telnet", true); + if(telnet) { + statTelnetServer(port+1); + } + service = statServer(); + synchronized (PerformanceProviderTest.class) { + while (true) { + try { + PerformanceProviderTest.class.wait(); + } catch (InterruptedException e) { + } + } + } + } + + private static void restartServer(int times, int wait, int sleep) throws Exception{ + if (service != null) { + service.unexport(); + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo").destroy(); + Thread.sleep(100); + } + for (int i = 0; i < times; i++) { + logger.info("restart times:" + i); + service = statServer(); + if (wait > 0) { + Thread.sleep(wait); + } + service.unexport(); + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo").destroy(); + if (sleep > 0) { + Thread.sleep(sleep); + } + } + service = statServer(); + } + + @SuppressWarnings("deprecation") + private static ServiceConfig statServer() throws Exception{ + final int port = PerformanceUtils.getIntProperty("port", 9911); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + final String threadpool = PerformanceUtils.getProperty(Constants.THREADPOOL_KEY, Constants.DEFAULT_THREADPOOL); + final int threads = PerformanceUtils.getIntProperty(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); + final int iothreads = PerformanceUtils.getIntProperty(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS); + final int buffer = PerformanceUtils.getIntProperty(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE); + + List scene = new ArrayList(); + scene.add("Transporter: " + transporter); + scene.add("Service Threads: " + threads); + PerformanceUtils.setScene(scene); + + DemoService demoService = new DemoServiceImpl(); + + ApplicationConfig application = new ApplicationConfig(); + application.setName("performance-provider"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress(RegistryConfig.NO_AVAILABLE); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(port); + protocol.setTransporter(transporter); + protocol.setSerialization(serialization); + protocol.setThreadpool(threadpool); + protocol.setThreads(threads); + protocol.setIothreads(iothreads); + protocol.setBuffer(buffer); + + ServiceConfig service = new ServiceConfig(); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.setInterfaceClass(DemoService.class); + service.setVersion("1.0.0"); + service.setRef(demoService); + service.export(); + + return service; + } + + private static ExchangeServer statTelnetServer(int port) throws Exception{ + // 启动服务器 + ExchangeServer telnetserver = Exchangers.bind("exchange://0.0.0.0:" + port , new ExchangeHandlerAdapter() { + public String telnet(Channel channel, String message) throws RemotingException { + if(message.equals("help")){ + return "support cmd: \r\n\tstart \r\n\tstop \r\n\tshutdown \r\n\trestart times [alive] [sleep] \r\ntelnet>"; + } else if(message.equals("stop")){ + if (service != null) { + logger.info("server closed:" + service); + service.unexport(); + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo").destroy(); + } + return "stop server\r\ntelnet>"; + } else if(message.startsWith("start")){ + try { + restartServer(0, 0, 0); + } catch (Exception e) { + e.printStackTrace(); + } + return "start server\r\ntelnet>"; + } else if(message.startsWith("shutdown")){ + System.exit(0); + return "start server\r\ntelnet>"; + } else if(message.startsWith("restart ")){ //r times [sleep] r 10 or r 10 100 + String[] args = message.split(" "); + int times = args.length > 1 ? Integer.parseInt(args[1]) : 1; + int alive = args.length > 2 ? Integer.parseInt(args[2]) : 0; + int sleep = args.length > 3 ? Integer.parseInt(args[3]) : 100; + try { + restartServer(times, alive, sleep); + } catch (Exception e) { + e.printStackTrace(); + } + return "restart server,times:"+times+" stop wait time: "+alive+",sleep time: " + sleep+" usage:restart [times] [wait] [sleep] \r\ntelnet>"; + } else{ + return "echo: " + message + "\r\ntelnet> "; + } + + } + }); + return telnetserver; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceUtils.java b/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceUtils.java new file mode 100644 index 0000000000..c8cd65e94d --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/performance/PerformanceUtils.java @@ -0,0 +1,136 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.performance; + +import java.net.NetworkInterface; +import java.net.SocketException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * PerformanceUtils + * + * @author william.liangf + */ +public class PerformanceUtils { + + public static String getProperty(String key, String defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return value.trim(); + } + + public static int getIntProperty(String key, int defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return Integer.parseInt(value.trim()); + } + public static boolean getBooleanProperty(String key, boolean defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return Boolean.parseBoolean(value.trim()); + } + + public static List getEnvironment() { + List environment = new ArrayList(); + environment.add("OS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch", "")); + environment.add("CPU: " + Runtime.getRuntime().availableProcessors() + " cores"); + environment.add("JVM: " + System.getProperty("java.vm.name") + " " + System.getProperty("java.runtime.version")); + environment.add("Memory: " + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().totalMemory()) + + " bytes (Max: " + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().maxMemory()) + " bytes)"); + NetworkInterface ni = PerformanceUtils.getNetworkInterface(); + if (ni != null) { + environment.add("Network: " + ni.getDisplayName()); + } + return environment; + } + + private static List scene = new ArrayList(); + + public static List getScene() { + return scene; + } + + public static void setScene(List scene) { + PerformanceUtils.scene = scene; + } + + private static final int WIDTH = 64; + + public static void printSeparator() { + StringBuilder pad = new StringBuilder(); + for (int i = 0; i < WIDTH; i ++) { + pad.append("-"); + } + System.out.println("+" + pad + "+"); + } + + public static void printBorder() { + StringBuilder pad = new StringBuilder(); + for (int i = 0; i < WIDTH; i ++) { + pad.append("="); + } + System.out.println("+" + pad + "+"); + } + + public static void printBody(String msg) { + StringBuilder pad = new StringBuilder(); + int len = WIDTH - msg.length() - 1; + if (len > 0) { + for (int i = 0; i < len; i ++) { + pad.append(" "); + } + } + System.out.println("| " + msg + pad + "|"); + } + + public static void printHeader(String msg) { + StringBuilder pad = new StringBuilder(); + int len = WIDTH - msg.length(); + if (len > 0) { + int half = len / 2; + for (int i = 0; i < half; i ++) { + pad.append(" "); + } + } + System.out.println("|" + pad + msg + pad + ((len % 2 == 0) ? "" : " ") + "|"); + } + + public static NetworkInterface getNetworkInterface() { + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (interfaces != null) { + while (interfaces.hasMoreElements()) { + try { + return interfaces.nextElement(); + } catch (Throwable e) { + } + } + } + } catch (SocketException e) { + } + return null; + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyException.java b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyException.java new file mode 100644 index 0000000000..576739cc35 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyException.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.util; + +/** + * User: heyman + * Date: 5/18/11 + * Time: 9:07 PM + */ +public class MyException extends Exception { + private static final long serialVersionUID = 1L; + + public MyException() { + super(); + } + + public MyException(String message, Throwable cause) { + super(message, cause); + } + + public MyException(String message) { + super(message); + } + + public MyException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyRuntimeException.java b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyRuntimeException.java new file mode 100644 index 0000000000..f6f3d20520 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyRuntimeException.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.util; + +/** + * User: heyman + * Date: 5/18/11 + * Time: 9:09 PM + */ +public class MyRuntimeException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public MyRuntimeException() { + super(); + } + + public MyRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + public MyRuntimeException(String message) { + super(message); + } + + public MyRuntimeException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyService.java b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyService.java new file mode 100644 index 0000000000..4c156c7f22 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyService.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.util; + +/** + * User: heyman + * Date: 5/18/11 + * Time: 4:10 PM + */ +public interface MyService { + public String echo(String input); + public void noReturn (String input); + public String throwException() throws MyException; + public String throwSystemException(); +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyServiceImpl.java b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyServiceImpl.java new file mode 100644 index 0000000000..6e53444241 --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/MyServiceImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.util; + +import org.apache.commons.logging.LogConfigurationException; + +/** + * User: heyman + * Date: 5/18/11 + * Time: 4:13 PM + */ +public class MyServiceImpl implements MyService{ + public String echo(String input) { + return input; + } + + public void noReturn(String input) { + } + + public String throwException() throws MyException { + throw new MyException("Exception throwed"); + } + + public String throwSystemException() { + throw new LogConfigurationException("system error"); + } +} \ No newline at end of file diff --git a/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/RpcConfigGetSetProxy.java b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/RpcConfigGetSetProxy.java new file mode 100644 index 0000000000..b2bcfb5b2c --- /dev/null +++ b/dubbo-config/src/test/java/com/alibaba/dubbo/rpc/util/RpcConfigGetSetProxy.java @@ -0,0 +1,169 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.config.AbstractConfig; + + +/** + * @author haomin.liuhm + * + */ +public class RpcConfigGetSetProxy { + + private static final String RPC_CONFIG_BASECLASS = AbstractConfig.class.getName(); + private static final Logger log = LoggerFactory.getLogger(RpcConfigGetSetProxy.class); + + + private Object proxiee = null; + private Class proxieeClass = null; + private Boolean isOk = false; + + public RpcConfigGetSetProxy(Object p){ + + if(p == null){ + return; + } + + if (!isKindOf(p.getClass(), RPC_CONFIG_BASECLASS)){ + return; + } + + proxiee = p; + //proxieeClass = c; + proxieeClass = p.getClass(); + isOk = true; + + } + + public boolean isOk(){ + return isOk; + } + + public Object setValue(String key, Object value){ + + if (!isOk()){ + return null; + } + + Method m = findSetMethod(key, value, proxieeClass); + return invoke(m, value); + } + + public Object getValue(String key){ + + if (!isOk()){ + return null; + } + + Method m = findGetMethod(key, proxieeClass); + return invoke(m, null); + } + + public static boolean isKindOf(Class c, String type){ + + // get the class def for obj and type + + Class tClass; + try { + tClass = Class.forName(type); + } catch (ClassNotFoundException e) { + return false; + } + + // check against type and superclasses + while ( c != null ) { + if ( c == tClass ) return true; + c = c.getSuperclass(); + } + + return false; + } + + private Object invoke(Method m, Object value) { + + if (m == null){ + return null; + } + + try { + if(value == null){ + return m.invoke(proxiee, (Object[])null); + }else{ + return m.invoke(proxiee, value); + } + } catch (IllegalArgumentException e) { + log.error("IllegalArgumentException", e); + return null; + } catch (IllegalAccessException e) { + log.error("IllegalAccessException", e); + return null; + } catch (InvocationTargetException e) { + log.error("InvocationTargetException", e); + return null; + } + } + + private Method findGetMethod(String key, Class clazz){ + + Method m = findMethod(key, null, "get", clazz); + if (m != null){ + return m; + } + + return findMethod(key, null, "is", clazz); + } + + private Method findSetMethod(String key, Object value, Class clazz){ + + return findMethod(key, value, "set", clazz); + } + + private Method getMethod(String methodName, Object value, Class clazz){ + + try{ + if (value == null){ + return clazz.getMethod(methodName, (Class[])null); + }else{ + return clazz.getMethod(methodName, value.getClass()); + } + }catch (SecurityException e) { + log.error("SecurityException: " + e.getMessage()); + return null; + } catch (NoSuchMethodException e) { + log.error("NoSuchMethodException: " + e.getMessage()); + return null; + } + } + + private Method findMethod(String key, Object value, String prefix, Class clazz){ + + if(key.length() < 2){ + return null; + } + + key = key.substring(0,1).toUpperCase() + key.substring(1); + String methodName = prefix + key; + + return getMethod(methodName, value, clazz); + } + +} \ No newline at end of file diff --git a/dubbo-config/src/test/resources/META-INF/services/com.alibaba.dubbo.registry.RegistryFactory b/dubbo-config/src/test/resources/META-INF/services/com.alibaba.dubbo.registry.RegistryFactory new file mode 100644 index 0000000000..c3a0d87e21 --- /dev/null +++ b/dubbo-config/src/test/resources/META-INF/services/com.alibaba.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +com.alibaba.dubbo.config.test.MockRegistryFactory diff --git a/dubbo-config/src/test/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol b/dubbo-config/src/test/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol new file mode 100644 index 0000000000..f83de720cd --- /dev/null +++ b/dubbo-config/src/test/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol @@ -0,0 +1 @@ +com.alibaba.dubbo.config.test.MockProtocol \ No newline at end of file diff --git a/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/explicit/consumer.xml b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/explicit/consumer.xml new file mode 100644 index 0000000000..3ff3ee9925 --- /dev/null +++ b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/explicit/consumer.xml @@ -0,0 +1,28 @@ + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/explicit/provider.xml b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/explicit/provider.xml new file mode 100644 index 0000000000..29d1f4f1ee --- /dev/null +++ b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/explicit/provider.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer.xml b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer.xml new file mode 100644 index 0000000000..6ad9a02b44 --- /dev/null +++ b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer2.xml b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer2.xml new file mode 100644 index 0000000000..6cad73cfd1 --- /dev/null +++ b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer_async.xml b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer_async.xml new file mode 100644 index 0000000000..8f690b1d6e --- /dev/null +++ b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/consumer_async.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/provider.xml b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/provider.xml new file mode 100644 index 0000000000..5556f8e9d1 --- /dev/null +++ b/dubbo-config/src/test/resources/com/alibaba/dubbo/callback/implicit/provider.xml @@ -0,0 +1,28 @@ + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/complex_consumer.xml b/dubbo-config/src/test/resources/complex_consumer.xml new file mode 100644 index 0000000000..7dc6078a31 --- /dev/null +++ b/dubbo-config/src/test/resources/complex_consumer.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/complex_provider.xml b/dubbo-config/src/test/resources/complex_provider.xml new file mode 100644 index 0000000000..15a90070a4 --- /dev/null +++ b/dubbo-config/src/test/resources/complex_provider.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/direct_consumer.xml b/dubbo-config/src/test/resources/direct_consumer.xml new file mode 100644 index 0000000000..01ccaf7cb7 --- /dev/null +++ b/dubbo-config/src/test/resources/direct_consumer.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/direct_provider.xml b/dubbo-config/src/test/resources/direct_provider.xml new file mode 100644 index 0000000000..c964fb3474 --- /dev/null +++ b/dubbo-config/src/test/resources/direct_provider.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/generic_consumer.xml b/dubbo-config/src/test/resources/generic_consumer.xml new file mode 100644 index 0000000000..c85e3953ba --- /dev/null +++ b/dubbo-config/src/test/resources/generic_consumer.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/generic_provider.xml b/dubbo-config/src/test/resources/generic_provider.xml new file mode 100644 index 0000000000..42e3bda91f --- /dev/null +++ b/dubbo-config/src/test/resources/generic_provider.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/injvm_consumer.xml b/dubbo-config/src/test/resources/injvm_consumer.xml new file mode 100644 index 0000000000..2700b9d3eb --- /dev/null +++ b/dubbo-config/src/test/resources/injvm_consumer.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/log4j.xml b/dubbo-config/src/test/resources/log4j.xml new file mode 100644 index 0000000000..7d71634640 --- /dev/null +++ b/dubbo-config/src/test/resources/log4j.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/performance_consumer.xml b/dubbo-config/src/test/resources/performance_consumer.xml new file mode 100644 index 0000000000..c36150ef33 --- /dev/null +++ b/dubbo-config/src/test/resources/performance_consumer.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/simple_consumer.xml b/dubbo-config/src/test/resources/simple_consumer.xml new file mode 100644 index 0000000000..efdd984c16 --- /dev/null +++ b/dubbo-config/src/test/resources/simple_consumer.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/simple_monitor.xml b/dubbo-config/src/test/resources/simple_monitor.xml new file mode 100644 index 0000000000..c0b1e2e0b0 --- /dev/null +++ b/dubbo-config/src/test/resources/simple_monitor.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/simple_provider.xml b/dubbo-config/src/test/resources/simple_provider.xml new file mode 100644 index 0000000000..3f9d2d2583 --- /dev/null +++ b/dubbo-config/src/test/resources/simple_provider.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/src/test/resources/simple_registry.xml b/dubbo-config/src/test/resources/simple_registry.xml new file mode 100644 index 0000000000..e490957554 --- /dev/null +++ b/dubbo-config/src/test/resources/simple_registry.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:9091 + + + + + \ No newline at end of file diff --git a/dubbo-container/pom.xml b/dubbo-container/pom.xml new file mode 100644 index 0000000000..37b7f11da1 --- /dev/null +++ b/dubbo-container/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-container + jar + Dubbo Container Module + The container module of dubbo project + + + com.alibaba + dubbo-config + ${project.parent.version} + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + true + + com.alibaba.dubbo.container.Main + + + + + + + \ No newline at end of file diff --git a/dubbo-container/src/main/java/com/alibaba/dubbo/container/Container.java b/dubbo-container/src/main/java/com/alibaba/dubbo/container/Container.java new file mode 100644 index 0000000000..2bdeffcce2 --- /dev/null +++ b/dubbo-container/src/main/java/com/alibaba/dubbo/container/Container.java @@ -0,0 +1,32 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.container; + +import com.alibaba.dubbo.common.Extension; + +/** + * TODO Comment of Container + * + * @author william.liangf + */ +@Extension("standalone") +public interface Container { + + void start(); + + void stop(); + +} \ No newline at end of file diff --git a/dubbo-container/src/main/java/com/alibaba/dubbo/container/Main.java b/dubbo-container/src/main/java/com/alibaba/dubbo/container/Main.java new file mode 100644 index 0000000000..20e98d8ad3 --- /dev/null +++ b/dubbo-container/src/main/java/com/alibaba/dubbo/container/Main.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.container; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.container.standalone.StandaloneContainer; + +/** + * Main + * + * @author william.liangf + */ +public class Main { + + public static void main(String[] args) { + final Container container = ExtensionLoader.getExtensionLoader(Container.class).getAdaptiveExtension(); + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + container.stop(); + } + }); + container.start(); + synchronized (StandaloneContainer.class) { + for (;;) { + try { + StandaloneContainer.class.wait(); + } catch (Throwable e) { + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-container/src/main/java/com/alibaba/dubbo/container/standalone/StandaloneContainer.java b/dubbo-container/src/main/java/com/alibaba/dubbo/container/standalone/StandaloneContainer.java new file mode 100644 index 0000000000..2c92fc3a24 --- /dev/null +++ b/dubbo-container/src/main/java/com/alibaba/dubbo/container/standalone/StandaloneContainer.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.container.standalone; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.container.Container; + +/** + * Standalone + * + * @author william.liangf + */ +@Extension("standalone") +public class StandaloneContainer implements Container { + + private static final Logger LOGGER = LoggerFactory.getLogger(StandaloneContainer.class); + + private static final String SPRING_CONFIG_KEY = "spring.config"; + + private static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml"; + + private ClassPathXmlApplicationContext context; + + public ApplicationContext getApplicationContext() { + return context; + } + + public void start() { + String configPath = System.getProperty(SPRING_CONFIG_KEY); + if (configPath == null || configPath.length() == 0) { + configPath = DEFAULT_SPRING_CONFIG; + } + context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+")); + context.start(); + LOGGER.info("Dubbo standalone container started!"); + } + + public void stop() { + try { + context.stop(); + } catch (Throwable e) { + LOGGER.error(e.getMessage(), e); + } + try { + context.close(); + } catch (Throwable e) { + LOGGER.error(e.getMessage(), e); + } + LOGGER.info("Dubbo standalone container stopped!"); + } + +} \ No newline at end of file diff --git a/dubbo-container/src/main/resources/META-INF/services/com.alibaba.dubbo.container.Container b/dubbo-container/src/main/resources/META-INF/services/com.alibaba.dubbo.container.Container new file mode 100644 index 0000000000..266056aeab --- /dev/null +++ b/dubbo-container/src/main/resources/META-INF/services/com.alibaba.dubbo.container.Container @@ -0,0 +1 @@ +com.alibaba.dubbo.container.standalone.StandaloneContainer \ No newline at end of file diff --git a/dubbo-container/src/test/java/com/alibaba/dubbo/container/standalone/StandaloneContainerTest.java b/dubbo-container/src/test/java/com/alibaba/dubbo/container/standalone/StandaloneContainerTest.java new file mode 100644 index 0000000000..e4d5fb62d7 --- /dev/null +++ b/dubbo-container/src/test/java/com/alibaba/dubbo/container/standalone/StandaloneContainerTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.container.standalone; + +import org.junit.Assert; +import org.junit.Test; + +/** + * StandaloneContainerTest + * + * @author william.liangf + */ +public class StandaloneContainerTest { + + @Test + public void testContainer() { + StandaloneContainer container = new StandaloneContainer(); + container.start(); + Assert.assertEquals(StandaloneContainer.class, container.getApplicationContext().getBean("container").getClass()); + container.stop(); + } + +} \ No newline at end of file diff --git a/dubbo-container/src/test/resources/META-INF/spring/test.xml b/dubbo-container/src/test/resources/META-INF/spring/test.xml new file mode 100644 index 0000000000..14242d1ecb --- /dev/null +++ b/dubbo-container/src/test/resources/META-INF/spring/test.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/dubbo-monitor/pom.xml b/dubbo-monitor/pom.xml new file mode 100644 index 0000000000..cbb2af1552 --- /dev/null +++ b/dubbo-monitor/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-monitor + jar + Dubbo Monitor Module + The monitor module of dubbo project + + + com.alibaba + dubbo-rpc + ${project.parent.version} + + + \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/Monitor.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/Monitor.java new file mode 100644 index 0000000000..0c12a53cc5 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/Monitor.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor; + +import com.alibaba.dubbo.common.Node; + +/** + * Monitor. (SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.monitor.MonitorFactory#getMonitor(com.alibaba.dubbo.common.URL) + * @author william.liangf + */ +public interface Monitor extends Node, MonitorService { + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/MonitorFactory.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/MonitorFactory.java new file mode 100644 index 0000000000..53d5acf478 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/MonitorFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * MonitorFactory. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +@Extension("dubbo") +public interface MonitorFactory { + + /** + * Create monitor. + * + * @param url + * @return + */ + @Adaptive("protocol") + Monitor getMonitor(URL url); + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/MonitorService.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/MonitorService.java new file mode 100644 index 0000000000..747df70bd1 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/MonitorService.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor; + +import com.alibaba.dubbo.common.URL; + +/** + * MonitorService. (SPI, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public interface MonitorService { + + String APPLICATION = "application"; + + String INTERFACE = "interface"; + + String METHOD = "method"; + + String GROUP = "group"; + + String VERSION = "version"; + + String CLIENT = "client"; + + String SERVER = "server"; + + String SUCCESS = "success"; + + String FAILURE = "failure"; + + String INPUT = "input"; + + String OUTPUT = "output"; + + String ELAPSED = "elapsed"; + + String CONCURRENT = "concurrent"; + + String MAX_INPUT = "max.input"; + + String MAX_OUTPUT = "max.output"; + + String MAX_ELAPSED = "max.elapsed"; + + String MAX_CONCURRENT = "max.concurrent"; + + /** + * count. + * + * @param statistics + */ + void count(URL statistics); + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/filter/MonitorFilter.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/filter/MonitorFilter.java new file mode 100644 index 0000000000..b5d8ae6dc8 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/filter/MonitorFilter.java @@ -0,0 +1,121 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.filter; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.monitor.Monitor; +import com.alibaba.dubbo.monitor.MonitorFactory; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * MonitorFilter. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +@Extension("monitor") +public class MonitorFilter implements Filter { + + private final ConcurrentMap concurrents = new ConcurrentHashMap(); + + private MonitorFactory monitorFactory; + + public void setMonitorFactory(MonitorFactory monitorFactory) { + this.monitorFactory = monitorFactory; + } + + // 调用过程拦截 + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + if (invoker.getUrl().hasParameter(Constants.MONITOR_KEY)) { + RpcContext context = RpcContext.getContext(); // 提供方必须在invoke()之前获取context信息 + long start = System.currentTimeMillis(); // 记录起始时间戮 + getConcurrent(invoker, invocation).incrementAndGet(); // 并发计数 + try { + Result result = invoker.invoke(invocation); // 让调用链往下执行 + collect(invoker, invocation, context, start, false); + return result; + } catch (RpcException e) { + collect(invoker, invocation, context, start, true); + throw e; + } finally { + getConcurrent(invoker, invocation).decrementAndGet(); // 并发计数 + } + } else { + return invoker.invoke(invocation); + } + } + + // 信息采集 + private void collect(Invoker invoker, Invocation invocation, RpcContext context, long start, boolean error) { + // ---- 服务信息获取 ---- + long elapsed = System.currentTimeMillis() - start; // 计算调用耗时 + int concurrent = getConcurrent(invoker, invocation).get(); // 当前并发数 + String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY); + String service = invoker.getInterface().getName(); // 获取服务名称 + String method = invocation.getMethodName(); // 获取方法名 + URL url = URL.valueOf(invoker.getUrl().getParameterAndDecoded(Constants.MONITOR_KEY)); + Monitor monitor = monitorFactory.getMonitor(url); + // ---- 服务提供方监控 ---- + String server = context.getLocalAddressString(); // 本地提供方地址 + if (invoker.getUrl().getAddress().equals(server)) { + monitor.count(new URL(invoker.getUrl().getProtocol(), NetUtils.getLocalHost(), context.getLocalPort()) + .addParameters(MonitorService.APPLICATION, application, + MonitorService.INTERFACE, service, + MonitorService.METHOD, method, + MonitorService.CLIENT, context.getRemoteHost(), + error ? MonitorService.FAILURE : MonitorService.SUCCESS, String.valueOf(1), + MonitorService.ELAPSED, String.valueOf(elapsed), + MonitorService.CONCURRENT, String.valueOf(concurrent))); + } + // ---- 服务消费方监控 ---- + context = RpcContext.getContext(); // 消费方必须在invoke()之后获取context信息 + server = context.getRemoteAddressString(); // 远程提供方地址 + if (invoker.getUrl().getAddress().equals(server)) { + monitor.count(new URL(invoker.getUrl().getProtocol(), NetUtils.getLocalHost(), 0) + .addParameters(MonitorService.APPLICATION, application, + MonitorService.INTERFACE, service, + MonitorService.METHOD, method, + MonitorService.SERVER, server, + error ? MonitorService.FAILURE : MonitorService.SUCCESS, String.valueOf(1), + MonitorService.ELAPSED, String.valueOf(elapsed), + MonitorService.CONCURRENT, String.valueOf(concurrent))); + } + } + + // 获取并发计数器 + private AtomicInteger getConcurrent(Invoker invoker, Invocation invocation) { + String key = invoker.getInterface().getName() + "." + invocation.getMethodName(); + AtomicInteger concurrent = concurrents.get(key); + if (concurrent == null) { + concurrents.putIfAbsent(key, new AtomicInteger()); + concurrent = concurrents.get(key); + } + return concurrent; + } + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactroy.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactroy.java new file mode 100644 index 0000000000..5af46d7237 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/AbstractMonitorFactroy.java @@ -0,0 +1,66 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.support; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.monitor.Monitor; +import com.alibaba.dubbo.monitor.MonitorFactory; + +/** + * AbstractMonitorFactroy. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +public abstract class AbstractMonitorFactroy implements MonitorFactory { + + // 注册中心获取过程锁 + private static final ReentrantLock LOCK = new ReentrantLock(); + + // 注册中心集合 Map + private static final Map MONITORS = new ConcurrentHashMap(); + + public static Collection getMonitors() { + return Collections.unmodifiableCollection(MONITORS.values()); + } + + public Monitor getMonitor(URL url) { + LOCK.lock(); + try { + Monitor monitor = MONITORS.get(url); + if (monitor != null) { + return monitor; + } + monitor = createMonitor(url); + if (monitor == null) { + throw new IllegalStateException("Can not create monitor " + url); + } + MONITORS.put(url, monitor); + return monitor; + } finally { + // 释放锁 + LOCK.unlock(); + } + } + + protected abstract Monitor createMonitor(URL url); + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/SimpleMonitorService.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/SimpleMonitorService.java new file mode 100644 index 0000000000..7a82e209f7 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/SimpleMonitorService.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.support; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.monitor.MonitorService; + +/** + * SimpleMonitorService + * + * @author william.liangf + */ +public class SimpleMonitorService implements MonitorService { + + private static final Logger logger = LoggerFactory.getLogger(SimpleMonitorService.class); + + public void count(URL statistics) { + logger.info(statistics.toString()); + } + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/DubboMonitor.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/DubboMonitor.java new file mode 100644 index 0000000000..95510cecd1 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/DubboMonitor.java @@ -0,0 +1,199 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.support.dubbo; + +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.jboss.netty.util.internal.ConcurrentHashMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.monitor.Monitor; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.rpc.Invoker; + +/** + * DubboMonitor + * + * @author william.liangf + */ +public class DubboMonitor implements Monitor { + + private static final Logger logger = LoggerFactory.getLogger(DubboMonitor.class); + + private static final int LENGTH = 10; + + // 定时任务执行器 + private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3, new NamedThreadFactory("DubboMonitorSenderTimer", true)); + + // 统计信息收集定时器 + private final ScheduledFuture sendFuture; + + private final Invoker monitorInvoker; + + private final MonitorService monitorService; + + private final long monitorInterval; + + private final ConcurrentMap> statisticsMap = new ConcurrentHashMap>(); + + public DubboMonitor(Invoker monitorInvoker, MonitorService monitorService) { + this.monitorInvoker = monitorInvoker; + this.monitorService = monitorService; + this.monitorInterval = monitorInvoker.getUrl().getPositiveIntParameter("interval", 60000); + // 启动统计信息收集定时器 + sendFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + public void run() { + // 收集统计信息 + try { + send(); + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at send statistic, cause: " + t.getMessage(), t); + } + } + }, monitorInterval, monitorInterval, TimeUnit.MILLISECONDS); + } + + public void send() { + if (logger.isInfoEnabled()) { + logger.info("Send statistics to monitor " + getUrl()); + } + for (Map.Entry> entry : statisticsMap.entrySet()) { + // 获取已统计数据 + Statistics statistics = entry.getKey(); + AtomicReference reference = entry.getValue(); + long[] numbers = reference.get(); + long success = numbers[0]; + long failure = numbers[1]; + long input = numbers[2]; + long output = numbers[3]; + long elapsed = numbers[4]; + long concurrent = numbers[5]; + long maxInput = numbers[6]; + long maxOutput = numbers[7]; + long maxElapsed = numbers[8]; + long maxConcurrent = numbers[9]; + + // 发送汇总信息 + URL url = statistics.getUrl(); + url.addParameter(MonitorService.SUCCESS, success); + url.addParameter(MonitorService.FAILURE, failure); + url.addParameter(MonitorService.INPUT, input); + url.addParameter(MonitorService.OUTPUT, output); + url.addParameter(MonitorService.ELAPSED, elapsed); + url.addParameter(MonitorService.CONCURRENT, concurrent); + url.addParameter(MonitorService.MAX_INPUT, maxInput); + url.addParameter(MonitorService.MAX_OUTPUT, maxOutput); + url.addParameter(MonitorService.MAX_ELAPSED, maxElapsed); + url.addParameter(MonitorService.MAX_CONCURRENT, maxConcurrent); + monitorService.count(url); + + // 减掉已统计数据 + long[] current; + long[] update = new long[LENGTH]; + do { + current = reference.get(); + if (current == null) { + update[0] = 0; + update[1] = 0; + update[2] = 0; + update[3] = 0; + update[4] = 0; + update[5] = 0; + } else { + update[0] = current[0] - success; + update[1] = current[1] - failure; + update[2] = current[2] - input; + update[3] = current[3] - output; + update[4] = current[4] - output; + update[5] = current[5] - output; + } + } while (! reference.compareAndSet(current, update)); + } + } + + public void count(URL url) { + // 读写统计变量 + int success = url.getIntParameter(MonitorService.SUCCESS); + int failure = url.getIntParameter(MonitorService.FAILURE); + int input = url.getIntParameter(MonitorService.INPUT); + int output = url.getIntParameter(MonitorService.OUTPUT); + int elapsed = url.getIntParameter(MonitorService.ELAPSED); + int concurrent = url.getIntParameter(MonitorService.CONCURRENT); + // 初始化原子引用 + Statistics statistics = new Statistics(url); + AtomicReference reference = statisticsMap.get(statistics); + if (reference == null) { + statisticsMap.putIfAbsent(statistics, new AtomicReference()); + reference = statisticsMap.get(statistics); + } + // CompareAndSet并发加入统计数据 + long[] current; + long[] update = new long[LENGTH]; + do { + current = reference.get(); + if (current == null) { + update[0] = success; + update[1] = failure; + update[2] = input; + update[3] = output; + update[4] = elapsed; + update[5] = concurrent; + update[6] = input; + update[7] = output; + update[8] = elapsed; + update[9] = concurrent; + } else { + update[0] = current[0] + success; + update[1] = current[1] + failure; + update[2] = current[2] + input; + update[3] = current[3] + output; + update[4] = current[4] + elapsed; + update[5] = current[5] + concurrent; + update[6] = current[6] > input ? current[6] : input; + update[7] = current[7] > output ? current[7] : output; + update[8] = current[8] > elapsed ? current[8] : elapsed; + update[9] = current[9] > concurrent ? current[9] : concurrent; + } + } while (! reference.compareAndSet(current, update)); + } + + public URL getUrl() { + return monitorInvoker.getUrl(); + } + + public boolean isAvailable() { + return monitorInvoker.isAvailable(); + } + + public void destroy() { + try { + sendFuture.cancel(true); + } catch (Throwable t) { + logger.error("Unexpected error occur at cancel sender timer, cause: " + t.getMessage(), t); + } + monitorInvoker.destroy(); + } + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/DubboMonitorFactroy.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/DubboMonitorFactroy.java new file mode 100644 index 0000000000..5371774bd5 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/DubboMonitorFactroy.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.support.dubbo; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.monitor.Monitor; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.monitor.support.AbstractMonitorFactroy; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +/** + * DefaultMonitorFactroy + * + * @author william.liangf + */ +@Extension("dubbo") +public class DubboMonitorFactroy extends AbstractMonitorFactroy { + + private Protocol protocol; + + private ProxyFactory proxyFactory; + + public void setProtocol(Protocol protocol) { + this.protocol = protocol; + } + + public void setProxyFactory(ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + } + + @Override + protected Monitor createMonitor(URL url) { + url = url.setProtocol(url.getParameter(Constants.MONITOR_KEY, Constants.REGISTRY_PROTOCOL)); + Invoker monitorInvoker = protocol.refer(MonitorService.class, url); + MonitorService monitorService = proxyFactory.getProxy(monitorInvoker); + return new DubboMonitor(monitorInvoker, monitorService); + } + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/Statistics.java b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/Statistics.java new file mode 100644 index 0000000000..859172c553 --- /dev/null +++ b/dubbo-monitor/src/main/java/com/alibaba/dubbo/monitor/support/dubbo/Statistics.java @@ -0,0 +1,200 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.support.dubbo; + +import java.io.Serializable; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.monitor.MonitorService; + +/** + * Statistics. (SPI, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public class Statistics implements Serializable { + + private static final long serialVersionUID = -6921183057683641441L; + + private URL url; + + private String application; + + private String service; + + private String method; + + private String group; + + private String version; + + private String client; + + private String server; + + public Statistics(URL url) { + this.url = url; + this.application = url.getParameter(MonitorService.APPLICATION); + this.service = url.getParameter(MonitorService.INTERFACE); + this.method = url.getParameter(MonitorService.METHOD); + this.group = url.getParameter(MonitorService.GROUP); + this.version = url.getParameter(MonitorService.VERSION); + this.client = url.getParameter(MonitorService.CLIENT); + this.server = url.getParameter(MonitorService.SERVER); + } + + public URL getUrl() { + return url; + } + + public void setUrl(URL url) { + this.url = url; + } + + public String getApplication() { + return application; + } + + public Statistics setApplication(String application) { + this.application = application; + return this; + } + + public String getService() { + return service; + } + + public Statistics setService(String service) { + this.service = service; + return this; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getMethod() { + return method; + } + + public Statistics setMethod(String method) { + this.method = method; + return this; + } + + public String getClient() { + return client; + } + + public Statistics setClient(String client) { + this.client = client; + return this; + } + + public String getServer() { + return server; + } + + public Statistics setServer(String server) { + this.server = server; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((application == null) ? 0 : application.hashCode()); + result = prime * result + ((client == null) ? 0 : client.hashCode()); + result = prime * result + ((group == null) ? 0 : group.hashCode()); + result = prime * result + ((method == null) ? 0 : method.hashCode()); + result = prime * result + ((server == null) ? 0 : server.hashCode()); + result = prime * result + ((service == null) ? 0 : service.hashCode()); + result = prime * result + ((url == null) ? 0 : url.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Statistics other = (Statistics) obj; + if (application == null) { + if (other.application != null) + return false; + } else if (!application.equals(other.application)) + return false; + if (client == null) { + if (other.client != null) + return false; + } else if (!client.equals(other.client)) + return false; + if (group == null) { + if (other.group != null) + return false; + } else if (!group.equals(other.group)) + return false; + if (method == null) { + if (other.method != null) + return false; + } else if (!method.equals(other.method)) + return false; + if (server == null) { + if (other.server != null) + return false; + } else if (!server.equals(other.server)) + return false; + if (service == null) { + if (other.service != null) + return false; + } else if (!service.equals(other.service)) + return false; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + if (version == null) { + if (other.version != null) + return false; + } else if (!version.equals(other.version)) + return false; + return true; + } + + @Override + public String toString() { + return url.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-monitor/src/main/resources/META-INF/services/com.alibaba.dubbo.monitor.MonitorFactory b/dubbo-monitor/src/main/resources/META-INF/services/com.alibaba.dubbo.monitor.MonitorFactory new file mode 100644 index 0000000000..d8223836e6 --- /dev/null +++ b/dubbo-monitor/src/main/resources/META-INF/services/com.alibaba.dubbo.monitor.MonitorFactory @@ -0,0 +1 @@ +com.alibaba.dubbo.monitor.support.dubbo.DubboMonitorFactroy \ No newline at end of file diff --git a/dubbo-monitor/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Filter b/dubbo-monitor/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Filter new file mode 100644 index 0000000000..1d4b7d3515 --- /dev/null +++ b/dubbo-monitor/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Filter @@ -0,0 +1 @@ +com.alibaba.dubbo.monitor.filter.MonitorFilter \ No newline at end of file diff --git a/dubbo-monitor/src/test/java/com/alibaba/dubbo/monitor/filter/MonitorFilterTest.java b/dubbo-monitor/src/test/java/com/alibaba/dubbo/monitor/filter/MonitorFilterTest.java new file mode 100644 index 0000000000..2c62c6bc94 --- /dev/null +++ b/dubbo-monitor/src/test/java/com/alibaba/dubbo/monitor/filter/MonitorFilterTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.filter; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.monitor.Monitor; +import com.alibaba.dubbo.monitor.MonitorFactory; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; + +/** + * MonitorFilterTest + * + * @author william.liangf + */ +public class MonitorFilterTest { + + private volatile URL lastStatistics; + + private volatile Invocation lastInvocation; + + private final Invoker serviceInvoker = new Invoker() { + public Class getInterface() { + return MonitorService.class; + } + public URL getUrl() { + try { + return URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880?" + Constants.APPLICATION_KEY + "=abc&" + Constants.MONITOR_KEY + "=" + URLEncoder.encode("dubbo://" + NetUtils.getLocalHost() + ":7070", "UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + public boolean isAvailable() { + return false; + } + public Result invoke(Invocation invocation) throws RpcException { + lastInvocation = invocation; + return null; + } + public void destroy() { + } + }; + + private MonitorFactory monitorFactory = new MonitorFactory() { + public Monitor getMonitor(final URL url) { + return new Monitor() { + public URL getUrl() { + return url; + } + public boolean isAvailable() { + return true; + } + public void destroy() { + } + public void count(URL statistics) { + MonitorFilterTest.this.lastStatistics = statistics; + } + }; + } + }; + + @Test + public void testFilter() throws Exception { + MonitorFilter monitorFilter = new MonitorFilter(); + monitorFilter.setMonitorFactory(monitorFactory); + Invocation invocation = new RpcInvocation("aaa", new Class[0], new Object[0]); + RpcContext.getContext().setRemoteAddress(NetUtils.getLocalHost(), 20880).setLocalAddress(NetUtils.getLocalHost(), 2345); + monitorFilter.invoke(serviceInvoker, invocation); + while (lastStatistics == null) { + Thread.sleep(10); + } + Assert.assertEquals("abc", lastStatistics.getParameter(MonitorService.APPLICATION)); + Assert.assertEquals(MonitorService.class.getName(), lastStatistics.getParameter(MonitorService.INTERFACE)); + Assert.assertEquals("aaa", lastStatistics.getParameter(MonitorService.METHOD)); + Assert.assertEquals(NetUtils.getLocalHost(), lastStatistics.getHost()); + Assert.assertEquals(NetUtils.getLocalHost() + ":20880", lastStatistics.getParameter(MonitorService.SERVER)); + Assert.assertEquals(null, lastStatistics.getParameter(MonitorService.CLIENT)); + Assert.assertEquals(1, lastStatistics.getIntParameter(MonitorService.SUCCESS)); + Assert.assertEquals(0, lastStatistics.getIntParameter(MonitorService.FAILURE)); + Assert.assertEquals(1, lastStatistics.getIntParameter(MonitorService.CONCURRENT)); + Assert.assertEquals(invocation, lastInvocation); + } + +} \ No newline at end of file diff --git a/dubbo-monitor/src/test/java/com/alibaba/dubbo/monitor/filter/support/dubbo/DubboMonitorTest.java b/dubbo-monitor/src/test/java/com/alibaba/dubbo/monitor/filter/support/dubbo/DubboMonitorTest.java new file mode 100644 index 0000000000..5ac0fa647a --- /dev/null +++ b/dubbo-monitor/src/test/java/com/alibaba/dubbo/monitor/filter/support/dubbo/DubboMonitorTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.monitor.filter.support.dubbo; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.monitor.support.dubbo.DubboMonitor; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * DubboMonitorTest + * + * @author william.liangf + */ +public class DubboMonitorTest { + + private volatile URL lastStatistics; + + private final Invoker monitorInvoker = new Invoker() { + public Class getInterface() { + return MonitorService.class; + } + public URL getUrl() { + return URL.valueOf("dubbo://127.0.0.1:7070?interval=1"); + } + public boolean isAvailable() { + return false; + } + public Result invoke(Invocation invocation) throws RpcException { + return null; + } + public void destroy() { + } + }; + + private final MonitorService monitorService = new MonitorService() { + + public void count(URL statistics) { + DubboMonitorTest.this.lastStatistics = statistics; + } + + }; + + @Test + public void testCount() throws Exception { + DubboMonitor monitor = new DubboMonitor(monitorInvoker, monitorService); + URL statistics = new URL("dubbo", "10.20.153.10", 0) + .addParameter(MonitorService.APPLICATION, "morgan") + .addParameter(MonitorService.INTERFACE, "MemberService") + .addParameter(MonitorService.METHOD, "findPerson") + .addParameter(MonitorService.CLIENT, "10.20.153.11") + .addParameter(MonitorService.SUCCESS, 1) + .addParameter(MonitorService.FAILURE, 0) + .addParameter(MonitorService.ELAPSED, 3) + .addParameter(MonitorService.MAX_ELAPSED, 3) + .addParameter(MonitorService.CONCURRENT, 1) + .addParameter(MonitorService.MAX_CONCURRENT, 1); + monitor.count(statistics); + while (lastStatistics == null) { + Thread.sleep(10); + } + Assert.assertEquals(statistics, lastStatistics); + monitor.destroy(); + } + +} \ No newline at end of file diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml new file mode 100644 index 0000000000..983002012c --- /dev/null +++ b/dubbo-registry/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-registry + jar + Dubbo Registry Module + The registry module of dubbo project + + + com.alibaba + dubbo-cluster + ${project.parent.version} + + + \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/NotifyListener.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/NotifyListener.java new file mode 100644 index 0000000000..4c9ef32154 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/NotifyListener.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.URL; + +/** + * NotifyListener. (API, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.registry.Registry#subscribe(URL, NotifyListener) + * @author william.liangf + */ +public interface NotifyListener { + + /** + * 当收到服务变更通知时触发 + * @param urls 含义同{@link Registry#register(String, Map)}的urls参数。 + */ + void notify(List urls); + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/Registry.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/Registry.java new file mode 100644 index 0000000000..7211b75ec9 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/Registry.java @@ -0,0 +1,29 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import com.alibaba.dubbo.common.Node; +import com.alibaba.dubbo.common.URL; + +/** + * Registry. (SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.registry.RegistryFactory#getRegistry(URL) + * @see com.alibaba.dubbo.registry.support.AbstractRegistry + * @author william.liangf + */ +public interface Registry extends Node, RegistryService { +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/RegistryFactory.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/RegistryFactory.java new file mode 100644 index 0000000000..2ab1105e31 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/RegistryFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * RegistryFactory. (SPI, Singleton, ThreadSafe) + * + * NOTE: RegistryFactory should NOT have default implement. + * + * @see com.alibaba.dubbo.registry.support.AbstractRegistryFactory + * @author william.liangf + */ +@Extension("dubbo") +public interface RegistryFactory { + + /** + * get registry. + * + * @param url registry url + * @return registry + */ + @Adaptive({"protocol"}) + Registry getRegistry(URL url); + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/RegistryService.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/RegistryService.java new file mode 100644 index 0000000000..911711b670 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/RegistryService.java @@ -0,0 +1,67 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import java.util.List; + +import com.alibaba.dubbo.common.URL; + +/** + * RegistryService + * + * @author william.liangf + */ +public interface RegistryService { + + /** + * 注册服务 + * + * @param url 服务提供者地址 + */ + void register(URL url); + + /** + * 取消注册服务 + * + * @param url 服务提供者地址 + */ + void unregister(URL url); + + /** + * 订阅服务 + * + * @param url 服务查询键值对,如:version=1.0.0&application=kylin + * @param listener 服务变更事件监听器 + */ + void subscribe(URL url, NotifyListener listener); + + /** + * 取消订阅服务 + * + * @param url 服务查询键值对,如:version=1.0.0&application=kylin + * @param listener 服务变更事件监听器 + */ + void unsubscribe(URL url, NotifyListener listener); + + /** + * 查询服务 + * + * @param url 服务查询键值对 + * @return 服务提供者者列表 + */ + List lookup(URL url); + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/directory/RegistryDirectory.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/directory/RegistryDirectory.java new file mode 100644 index 0000000000..a12422e7b6 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/directory/RegistryDirectory.java @@ -0,0 +1,468 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.directory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Router; +import com.alibaba.dubbo.rpc.cluster.RouterFactory; +import com.alibaba.dubbo.rpc.cluster.support.AbstractDirectory; +import com.alibaba.dubbo.rpc.cluster.support.ClusterUtils; + +/** + * RegistryDirectory + * + * @author william.liangf + */ +public class RegistryDirectory extends AbstractDirectory implements NotifyListener { + + private static final Logger logger = LoggerFactory.getLogger(RegistryDirectory.class); + + private static final String ALL_METHOD_NAME = "*"; + + private volatile boolean forbidden = false; + + private volatile boolean destroyed = false; + + private final String serviceKey; + + private final Class serviceType; + + private volatile URL directoryUrl; + + private volatile Map queryMap; + + // Map cache service url to invoker mapping. + private Map> urlInvokerMap = new ConcurrentHashMap>(); + + // Map cache service method to invokers mapping. + private volatile Map>> methodInvokerMap; + + private volatile Protocol protocol; + + private volatile Registry registry; + + public RegistryDirectory(Class serviceType, URL url) { + super(url); + if(serviceType == null ) + throw new IllegalArgumentException("service type is null."); + if(url.getServiceKey() == null || url.getServiceKey().length() == 0) + throw new IllegalArgumentException("registry serviceKey is null."); + this.serviceType = serviceType; + this.serviceKey = url.getServiceKey(); + this.queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(RpcConstants.REFER_KEY)); + this.directoryUrl = url.removeParameter(RpcConstants.REFER_KEY).addParameters(queryMap); + } + + public void setProtocol(Protocol protocol) { + this.protocol = protocol; + } + + public void setRegistry(Registry registry) { + this.registry = registry; + } + + public void destroy() { + if(destroyed) { + return; + } + destroyed = true; + // unsubscribe. + try { + if(registry != null && registry.isAvailable()) { + registry.unsubscribe(directoryUrl, this); + } + } catch (Throwable t) { + logger.warn("unexpeced error when unsubscribe service " + serviceKey + "from registry" + registry.getUrl().getAddress(), t); + } + try { + destroyAllInvokers(); + } catch (Throwable t) { + logger.warn("Failed to destroy service " + serviceKey, t); + } + } + + public synchronized void notify(List urls) { + if (urls == null || urls.size() == 0) { // 黑白名单限制 + this.forbidden = true; // 禁止访问 + this.methodInvokerMap = null; // 置空列表 + destroyAllInvokers(); // 关闭所有Invoker + } else { + this.forbidden = false; // 允许访问 + List invokerUrls = new ArrayList(); + List routerUrls = new ArrayList(); + for (URL url : urls) { + if (RpcConstants.ROUTE_PROTOCOL.equals(url.getProtocol())) { + if (! routerUrls.contains(url)) { + routerUrls.add(url); + } + } else if (ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(url.getProtocol())) { + if (! invokerUrls.contains(url)) { + invokerUrls.add(url); + } + } else { + logger.error("Unsupported protocol " + url.getProtocol() + " in notified url " + url + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost()); + } + } + + Map> newUrlInvokerMap = null ; + Map>> newMethodInvokerMap = null ; + List routers = null ; + Map> oldUrlInvokerMap = urlInvokerMap; + //transaction convert + { + routers = toRouters(routerUrls); + newUrlInvokerMap = toInvokers(invokerUrls); // 将URL列表转成Invoker列表 + newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); // 换方法名映射Invoker列表 + } + // state change + { + this.methodInvokerMap = newMethodInvokerMap; + this.urlInvokerMap = newUrlInvokerMap; + if(routers != null){ // null - do nothing + setRouters(routers); + } + try{ + destroyUnusedInvokers(oldUrlInvokerMap,newUrlInvokerMap); // 关闭未使用的Invoker + }catch (Exception e) { + logger.warn("destroyUnusedInvokers error. ", e); + } + } + } + } + + /** + * + * @param urls + * @return null : no routers ,do nothing + * else :routers list + */ + private List toRouters(List urls) { + //no router urls , do nothing + if(urls == null || urls.size() < 1){ + return null ; + } + List routers = new ArrayList(); + + // on these conditions: clear all current routers + // 1. there is only one route url + // 2. with type = clear + if(urls.size() == 1){ + URL u = urls.get(0); + // clean current routers + if(RpcConstants.ROUTER_TYPE_CLEAR.equals(u.getParameter(RpcConstants.ROUTER_KEY))){ + return routers; + } + } + + if (urls != null && urls.size() > 0) { + for (URL url : urls) { + String router_type = url.getParameter(RpcConstants.ROUTER_KEY); + if (router_type == null || router_type.length() == 0){ + logger.warn("Router url:\"" + url.toString() + "\" does not contain " + RpcConstants.ROUTER_KEY + ", router creation ignored!"); + continue; + } + routers.add(ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(router_type).getRouter(url)); +// routers.add(routerFactory.getRouter(url.setProtocol(router_type))); + } + } + return routers; + } + + /** + * 将urls转成invokers + * + * @param urls + * @param query + * @return invokers + */ + private Map> toInvokers(List urls) { + if(urls == null || urls.size() == 0){ + return null; + } + Map> newUrlInvokerMap = new ConcurrentHashMap>(); + Set keys = new HashSet(); + for (URL url : urls) { + String key = url.toFullString(); // URL参数是排序的 + if (keys.contains(key)) { // 重复URL + continue; + } + keys.add(key); + // 缓存key为没有合并消费端参数的URL,不管消费端如何合并参数,如果服务端URL发生变化,则重新refer + Invoker invoker = urlInvokerMap.get(key); + if (invoker == null) { // 缓存中没有,重新refer + try { + if ((url.getPath() == null || url.getPath().length() == 0) + && "dubbo".equals(url.getProtocol())) { // 兼容1.0 + String path = directoryUrl.getPath(); + int i = path.indexOf('/'); + if (i >= 0) { + path = path.substring(i + 1); + } + i = path.lastIndexOf(':'); + if (i >= 0) { + path = path.substring(0, i); + } + url = url.setPath(path); + } + url = ClusterUtils.mergeUrl(url, queryMap); // 合并消费端参数 + this.directoryUrl = this.directoryUrl.addParametersIfAbsent(url.getParameters()); // 合并提供者参数 + url = url.addParameter(Constants.CHECK_KEY, String.valueOf(false));// 不检查连接是否成功,总是创建Invoker + invoker = protocol.refer(serviceType, url); + } catch (Throwable t) { + logger.error("Failed to refer invoker for interface:"+serviceType+",url:("+url+")" + t.getMessage(), t); + } + if (invoker != null) { // 将新的引用放入缓存 + newUrlInvokerMap.put(key, invoker); + } + }else { + newUrlInvokerMap.put(key, invoker); + } + } + keys.clear(); + return newUrlInvokerMap; + } + + /** + * 将invokers列表转成与方法的映射关系 + * + * @param invokersMap Invoker列表 + * @return Invoker与方法的映射关系 + */ + private Map>> toMethodInvokers(Map> invokersMap) { + Map>> methodInvokerMap = new HashMap>>(); + if (invokersMap != null && invokersMap.size() > 0) { + List> invokersList = new ArrayList>(); + for (Invoker invoker : invokersMap.values()) { + String parameter = invoker.getUrl().getParameter(Constants.METHODS_KEY); + if (parameter != null && parameter.length() > 0) { + String[] methods = Constants.COMMA_SPLIT_PATTERN.split(parameter); + if (methods != null && methods.length > 0) { + for (String method : methods) { + if (method != null && method.length() > 0 + && ! ALL_METHOD_NAME.equals(method)) { + List> methodInvokers = methodInvokerMap.get(method); + if (methodInvokers == null) { + methodInvokers = new ArrayList>(); + methodInvokerMap.put(method, methodInvokers); + } + methodInvokers.add(invoker); + } + } + } + } + invokersList.add(invoker); + } + methodInvokerMap.put(ALL_METHOD_NAME, invokersList); + } + // sort and unmodifiable + for (String method : new HashSet(methodInvokerMap.keySet())) { + List> methodInvokers = methodInvokerMap.get(method); + Collections.sort(methodInvokers, InvokerComparator.getComparator()); + methodInvokerMap.put(method, Collections.unmodifiableList(methodInvokers)); + } + return Collections.unmodifiableMap(methodInvokerMap); + } + + /** + * 关闭所有Invoker + */ + private void destroyAllInvokers() { + if(urlInvokerMap != null) { + for (Invoker invoker : new ArrayList>(urlInvokerMap.values())) { + try { + invoker.destroy(); + } catch (Throwable t) { + logger.warn("Failed to destroy service " + serviceKey + " to provider " + invoker.getUrl(), t); + } + } + urlInvokerMap.clear(); + } + methodInvokerMap = null; + } + + /** + * 检查缓存中的invoker是否需要被destroy + * 如果url中指定refer.autodestroy=false,则只增加不减少,可能会有refer泄漏, + * + * @param invokers + */ + private void destroyUnusedInvokers(Map> oldUrlInvokerMap, Map> newUrlInvokerMap) { + if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) { + destroyAllInvokers(); + return; + } + boolean autodestroy = true ; + // 如果URL中指定了autodestroy=false,则不关闭旧的连接 + for(Invoker invoker : newUrlInvokerMap.values() ){ + if (invoker != null && invoker.getUrl() != null){ + autodestroy = invoker.getUrl().getBooleanParameter("refer.autodestroy", true); + } + break; + } + if(! autodestroy) { + if(logger.isWarnEnabled()) { + logger.warn("url.param[refer.autodestroy=false] is false. may have reference leak. recommend(default) true"); + } + return; + } + + // check deleted invoker + List deleted = null; + if (oldUrlInvokerMap != null) { + Collection> newInvokers = newUrlInvokerMap.values(); + for (Map.Entry> entry : oldUrlInvokerMap.entrySet()){ + if (! newInvokers.contains(entry.getValue())) { + if (deleted == null) { + deleted = new ArrayList(); + } + deleted.add(entry.getKey()); + } + } + } + + if (deleted != null) { + for (String url : deleted){ + if (url != null ) { + Invoker invoker = oldUrlInvokerMap.remove(url); + if (invoker != null) { + try { + invoker.destroy(); + if(logger.isDebugEnabled()){ + logger.debug("destory invoker["+invoker.getUrl()+"] success. "); + } + } catch (Exception e) { + logger.warn("destory invoker["+invoker.getUrl()+"] faild. " + e.getMessage(), e); + } + } + } + } + } + } + + public List> doList(Invocation invocation) { + if (forbidden) { + throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "Forbid consumer " + NetUtils.getLocalHost() + " access service " + getInterface().getName() + " from registry " + getUrl().getAddress() + " use dubbo version " + Version.getVersion() + ", Please check registry access list (whitelist/blacklist)."); + } + List> invokers = null; + if (methodInvokerMap != null && methodInvokerMap.size() > 0) { + String methodName = invocation.getMethodName(); + Object[] args = invocation.getArguments(); + + // Generic invoke: Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException; + if (Constants.$INVOKE.equals(methodName) + && args != null && args.length == 3 + && args[0] instanceof String + && args[2] instanceof Object[]) { + methodName = (String) args[0]; + args = (Object[]) args[2]; + } + if(args != null && args.length > 0 && args[0] != null + && (args[0] instanceof String || args[0].getClass().isEnum())) { + invokers = methodInvokerMap.get(methodName + "." + args[0]); // 可根据第一个参数枚举路由 + } + if(invokers == null) { + invokers = methodInvokerMap.get(methodName); + } + if(invokers == null) { + invokers = methodInvokerMap.get(ALL_METHOD_NAME); + } + if(invokers == null) { + Iterator>> iterator = methodInvokerMap.values().iterator(); + if (iterator.hasNext()) { + invokers = iterator.next(); + } + } + } + return invokers == null ? new ArrayList>(0) : invokers; + } + + public Class getInterface() { + return serviceType; + } + + public URL getUrl() { + return directoryUrl; + } + + public boolean isAvailable() { + Map> map = urlInvokerMap; + if (map != null && map.size() > 0) { + for (Invoker invoker : new ArrayList>(map.values())) { + if (invoker.isAvailable()) { + return true; + } + } + } + return false; + } + + /** + * Haomin: added for test purpose + */ + public Map> getUrlInvokerMap(){ + return urlInvokerMap; + } + + /** + * Haomin: added for test purpose + */ + public Map>> getMethodInvokerMap(){ + return methodInvokerMap; + } + + private static class InvokerComparator implements Comparator> { + + private static final InvokerComparator comparator = new InvokerComparator(); + + public static InvokerComparator getComparator() { + return comparator; + } + + private InvokerComparator() {} + + public int compare(Invoker o1, Invoker o2) { + return o1.getUrl().toString().compareTo(o2.getUrl().toString()); + } + + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/protocol/RegistryProtocol.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/protocol/RegistryProtocol.java new file mode 100644 index 0000000000..25e8e82114 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/protocol/RegistryProtocol.java @@ -0,0 +1,143 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.protocol; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.directory.RegistryDirectory; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.support.InvokerWrapper; + +/** + * RegistryProtocol + * + * @author william.liangf + */ +@Extension(Constants.REGISTRY_PROTOCOL) +public class RegistryProtocol implements Protocol { + + private Cluster cluster; + + public void setCluster(Cluster cluster) { + this.cluster = cluster; + } + + private Protocol protocol; + + public void setProtocol(Protocol protocol) { + this.protocol = protocol; + } + + private RegistryFactory registryFactory; + + public void setRegistryFactory(RegistryFactory registryFactory) { + this.registryFactory = registryFactory; + } + + public int getDefaultPort() { + return 9090; + } + + private final Map> bounds = new ConcurrentHashMap>(); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Exporter export(final Invoker invoker) throws RpcException { + String export = invoker.getUrl().getParameterAndDecoded(RpcConstants.EXPORT_KEY); + if (export == null || export.length() == 0) { + throw new IllegalArgumentException("The registry export url is null! registry: " + invoker.getUrl()); + } + + URL url = URL.valueOf(export); + final String key = url.removeParameters("dynamic", "enabled").toFullString(); + Exporter exporter = (Exporter) bounds.get(key); + if (exporter == null) { + synchronized (bounds) { + exporter = (Exporter) bounds.get(key); + if (exporter == null) { + exporter = protocol.export(new InvokerWrapper(invoker, url)); + bounds.put(key, exporter); + } + } + } + + URL registryUrl = invoker.getUrl(); + if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) { + String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY); + registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY); + } + final Exporter serviceExporter = exporter; + final URL serviceUrl = url.removeParameters(getFilteredKeys(url)); + final Registry registry = registryFactory.getRegistry(registryUrl); + registry.register(serviceUrl); + + return new Exporter() { + public Invoker getInvoker() { + return invoker; + } + public void unexport() { + bounds.remove(key); + try { + registry.unregister(serviceUrl); + } finally { + serviceExporter.unexport(); + } + } + }; + } + + public Invoker refer(Class type, URL url) throws RpcException { + url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY); + Registry registry = registryFactory.getRegistry(url); + RegistryDirectory directory = new RegistryDirectory(type, url); + directory.setRegistry(registry); + directory.setProtocol(protocol); + registry.subscribe(directory.getUrl(), directory); + return cluster.merge(directory); + } + + //过滤URL中不需要输出的参数(以点号开头的) + private static String[] getFilteredKeys(URL url) { + Map params = url.getParameters(); + if (params != null && !params.isEmpty()) { + List filteredKeys = new ArrayList(); + for (Map.Entry entry : params.entrySet()) { + if (entry != null && entry.getKey() != null && entry.getKey().startsWith(Constants.HIDE_KEY_PREFIX)) { + filteredKeys.add(entry.getKey()); + } + } + return filteredKeys.toArray(new String[filteredKeys.size()]); + } else { + return new String[] {}; + } + } + + public void destroy() { + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/status/RegistryStatusChecker.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/status/RegistryStatusChecker.java new file mode 100644 index 0000000000..846edda01a --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/status/RegistryStatusChecker.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.status; + +import java.util.Collection; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; + +/** + * RegistryStatusChecker + * + * @author william.liangf + */ +@Extension("registry") +public class RegistryStatusChecker implements StatusChecker { + + public Status check() { + Collection regsitries = AbstractRegistryFactory.getRegistries(); + if (regsitries == null || regsitries.size() == 0) { + return new Status(Status.Level.UNKNOWN); + } + Status.Level level = Status.Level.OK; + StringBuilder buf = new StringBuilder(); + for (Registry registry : regsitries) { + if (buf.length() > 0) { + buf.append(","); + } + buf.append(registry.getUrl().getAddress()); + if (! registry.isAvailable()) { + level = Status.Level.ERROR; + buf.append("(disconnected)"); + } else { + buf.append("(connected)"); + } + } + return new Status(level, buf.toString()); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java new file mode 100644 index 0000000000..e5122e582e --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java @@ -0,0 +1,63 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; + +/** + * 嵌入式注册中心实现,不开端口,只是map进行存储查询.不需要显示声明 + * + * @author chao.liuc + * @author william.liangf + */ +public abstract class AbstractRegistry extends AbstractRegistryService implements Registry { + + private final URL registryUrl; + + public AbstractRegistry(URL url) { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + this.registryUrl = url; + } + + public URL getUrl() { + return registryUrl; + } + + public InetSocketAddress getLocalAddress() { + return registryUrl.getInetSocketAddress(); + } + + public InetSocketAddress getRemoteAddress() { + return registryUrl.getInetSocketAddress(); + } + + public boolean isAvailable() { + return true; + } + + public void destroy() { + } + + public String toString() { + return getUrl().toString(); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryFactory.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryFactory.java new file mode 100644 index 0000000000..37a063bb36 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryFactory.java @@ -0,0 +1,106 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; + +/** + * RegistryLocators. (API, Static, ThreadSafe) + * + * @see com.alibaba.dubbo.registry.RegistryFactory + * @author william.liangf + */ +public abstract class AbstractRegistryFactory implements RegistryFactory { + + // 日志输出 + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRegistryFactory.class); + + // 注册中心获取过程锁 + protected static final ReentrantLock LOCK = new ReentrantLock(); + + // 注册中心集合 Map + protected static final Map REGISTRIES = new ConcurrentHashMap(); + + public Registry getRegistry(URL url) { + // 锁定注册中心获取过程,保证注册中心单一实例 + LOCK.lock(); + try { + Registry registry = REGISTRIES.get(getCacheKey(url)); + if (registry != null) { + return registry; + } + registry = createRegistry(url); + if (registry == null) { + throw new IllegalStateException("Can not create registry " + url); + } + REGISTRIES.put(getCacheKey(url), registry); + return registry; + } finally { + // 释放锁 + LOCK.unlock(); + } + } + + protected abstract Registry createRegistry(URL url); + + /** + * 获取所有注册中心 + * + * @return 所有注册中心 + */ + public static Collection getRegistries() { + return Collections.unmodifiableCollection(REGISTRIES.values()); + } + + /** + * 关闭所有已创建注册中心 + */ + public static void destroyAll() { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Close all registries " + getRegistries()); + } + // 锁定注册中心关闭过程 + LOCK.lock(); + try { + for (Registry registry : getRegistries()) { + try { + registry.destroy(); + } catch (Throwable e) { + LOGGER.error(e.getMessage(), e); + } + } + REGISTRIES.clear(); + } finally { + // 释放锁 + LOCK.unlock(); + } + } + + protected static String getCacheKey(URL url){ + return url.getProtocol() + "://" + url.getUsername() + ":" + url.getPassword() + "@" + url.getAddress(); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryService.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryService.java new file mode 100644 index 0000000000..1d0e6a219e --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryService.java @@ -0,0 +1,214 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.RegistryService; + +/** + * AbstractRegistryService + * + * @author william.liangf + */ +public abstract class AbstractRegistryService implements RegistryService { + + // 日志输出 + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + // 已注册的服务 + // Map> + private final ConcurrentMap> registered = new ConcurrentHashMap>(); + + // 已订阅的服务 + // Map + private final ConcurrentMap> subscribed = new ConcurrentHashMap>(); + + // 已通知的服务 + // Map> + private final ConcurrentMap> notified = new ConcurrentHashMap>(); + + // 已订阅服务的监听器列表 + // Map> + private final ConcurrentMap> notifyListeners = new ConcurrentHashMap>(); + + public void register(URL url) { + if (logger.isInfoEnabled()) { + logger.info("Register service: " + url.getServiceKey() + ",url:" + url); + } + register(url.getServiceKey(), url); + } + + public void unregister(URL url) { + if (logger.isInfoEnabled()) { + logger.info("Unregister service: " + url.getServiceKey() + ",url:" + url); + } + unregister(url.getServiceKey(), url); + } + + public void subscribe(URL url, NotifyListener listener) { + if (logger.isInfoEnabled()) { + logger.info("Subscribe service: " + url.getServiceKey() + ",url:" + url); + } + subscribe(url.getServiceKey(), url.getParameters(), listener); + } + + public void unsubscribe(URL url, NotifyListener listener) { + if (logger.isInfoEnabled()) { + logger.info("Unsubscribe service: " + url.getServiceKey() + ",url:" + url); + } + unsubscribe(url.getServiceKey(), url.getParameters(), listener); + } + + public List lookup(URL url) { + return getRegistered(url.getServiceKey()); + } + + public void register(String service, URL url) { + if (service == null) { + throw new IllegalArgumentException("service == null"); + } + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + List urls = registered.get(service); + if (urls == null) { + registered.putIfAbsent(service, new CopyOnWriteArrayList()); + urls = registered.get(service); + } + if (! urls.contains(url)) { + urls.add(url); + } + } + + public void unregister(String service, URL url) { + if (service == null) { + throw new IllegalArgumentException("service == null"); + } + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + List urls = registered.get(service); + if (urls != null) { + urls.remove(url); + } + } + + public void subscribe(String service, Map parameters, NotifyListener listener) { + if (service == null) { + throw new IllegalArgumentException("service == null"); + } + if (parameters == null) { + throw new IllegalArgumentException("parameters == null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener == null"); + } + subscribed.put(service, parameters); + List listeners = notifyListeners.get(service); + if (listeners == null) { + notifyListeners.putIfAbsent(service, new CopyOnWriteArrayList()); + listeners = notifyListeners.get(service); + } + listeners.add(listener); + } + + public void unsubscribe(String service, Map parameters, NotifyListener listener) { + if (service == null) { + throw new IllegalArgumentException("service == null"); + } + if (parameters == null) { + throw new IllegalArgumentException("parameters == null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener == null"); + } + subscribed.remove(service); + List listeners = notifyListeners.get(service); + if (listeners != null) { + listeners.remove(listener); + } + } + + private void doNotify(String service, List urls) { + notified.put(service, urls); + List listeners = notifyListeners.get(service); + if (listeners != null) { + for (NotifyListener listener : listeners) { + try { + notify(service, urls, listener); + } catch (Throwable t) { + logger.error("Failed to notify registry event, service: " + service + ", urls: " + urls + ", cause: " + t.getMessage(), t); + } + } + } + } + + protected void notify(String service, List urls, NotifyListener listener) { + listener.notify(urls); + } + + protected final void forbid(String service) { + doNotify(service, new ArrayList(0)); + } + + protected final void notify(String service, List urls) { + if (service == null || service.length() == 0 + || urls == null || urls.size() == 0) { + return; + } + doNotify(service, urls); + } + + public Map> getRegistered() { + return Collections.unmodifiableMap(registered); + } + + public List getRegistered(String service) { + return Collections.unmodifiableList(registered.get(service)); + } + + public Map> getSubscribed() { + return Collections.unmodifiableMap(subscribed); + } + + public Map getSubscribed(String service) { + return subscribed.get(service); + } + + public Map> getNotified() { + return Collections.unmodifiableMap(notified); + } + + public List getNotified(String service) { + return Collections.unmodifiableList(notified.get(service)); + } + + public Map> getListeners() { + return Collections.unmodifiableMap(notifyListeners); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/SimpleRegistryExporter.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/SimpleRegistryExporter.java new file mode 100644 index 0000000000..9e14423b3b --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/SimpleRegistryExporter.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support; + +import java.io.IOException; +import java.net.ServerSocket; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +/** + * SimpleRegistryExporter + * + * @author william.liangf + */ +public class SimpleRegistryExporter { + + private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + public synchronized static Exporter exportIfAbsent(int port) { + try { + new ServerSocket(port).close(); + return export(port); + } catch (IOException e) { + return null; + } + } + + public static Exporter export(int port) { + RegistryService registryService = new SimpleRegistryService(); + return protocol.export(proxyFactory.getInvoker(registryService, RegistryService.class, + new URL("dubbo", NetUtils.getLocalHost(), port, RegistryService.class.getName()) + .setPath(RegistryService.class.getName()) + .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName()) + .addParameter(Constants.VERSION_KEY, "0.0.0") + .addParameter(RpcConstants.CLUSTER_STICKY_KEY, "true") + .addParameter(RpcConstants.CALLBACK_INSTANCES_LIMIT_KEY, "1000") + .addParameter("ondisconnect", "disconnect") + .addParameter("subscribe.1.callback", "true") + .addParameter("unsubscribe.1.callback", "false"))); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/SimpleRegistryService.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/SimpleRegistryService.java new file mode 100644 index 0000000000..9aa37d76db --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/SimpleRegistryService.java @@ -0,0 +1,148 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * SimpleRegistryService + * + * @author william.liangf + */ +public class SimpleRegistryService extends AbstractRegistryService { + + private final ConcurrentMap> remoteRegistered = new ConcurrentHashMap>(); + + private final ConcurrentMap> remoteListeners = new ConcurrentHashMap>(); + + private final static Logger logger = LoggerFactory.getLogger(SimpleRegistryService.class); + + private List registries; + + @Override + public void register(String service, URL url) { + super.register(service, url); + String client = RpcContext.getContext().getRemoteAddressString(); + Map urls = remoteRegistered.get(client); + if (urls == null) { + remoteRegistered.putIfAbsent(client, new ConcurrentHashMap()); + urls = remoteRegistered.get(client); + } + urls.put(service, url); + notify(service, getRegistered().get(service)); + } + + @Override + public void unregister(String service, URL url) { + super.unregister(service, url); + String client = RpcContext.getContext().getRemoteAddressString(); + Map urls = remoteRegistered.get(client); + if (urls != null && urls.size() > 0) { + urls.remove(service); + } + notify(service, getRegistered().get(service)); + } + + @Override + public void subscribe(String service, Map parameters, NotifyListener listener) { + String client = RpcContext.getContext().getRemoteAddressString(); + if (logger.isInfoEnabled()){ + logger.info("[subscribe] service: "+service + ",client:"+ client); + } + List urls = getRegistered().get(service); + if ((com.alibaba.dubbo.registry.RegistryService.class.getName() + ":0.0.0").equals(service) + && (urls == null || urls.size() == 0)) { + register(service, new URL("dubbo", + NetUtils.getLocalHost(), + RpcContext.getContext().getLocalPort(), + com.alibaba.dubbo.registry.RegistryService.class.getName(), + parameters)); + List rs = registries; + if (rs != null && rs.size() > 0) { + for (String registry : rs) { + register(service, UrlUtils.parseURL(registry, parameters)); + } + } + } + super.subscribe(service, parameters, listener); + + Map listeners = remoteListeners.get(client); + if (listeners == null) { + remoteListeners.putIfAbsent(client, new ConcurrentHashMap()); + listeners = remoteListeners.get(client); + } + listeners.put(service, listener); + urls = getRegistered().get(service); + if (urls != null && urls.size() > 0) { + listener.notify(urls); + } + + + } + + @Override + public void unsubscribe(String service, Map parameters, NotifyListener listener) { + super.unsubscribe(service, parameters, listener); + String client = RpcContext.getContext().getRemoteAddressString(); + Map listeners = remoteListeners.get(client); + if (listeners != null && listeners.size() > 0) { + listeners.remove(service); + } + List urls = getRegistered().get(service); + if (urls != null && urls.size() > 0) { + listener.notify(urls); + } + } + + public void disconnect() { + String client = RpcContext.getContext().getRemoteAddressString(); + if (logger.isInfoEnabled()) { + logger.info("Disconnected " + client); + } + ConcurrentMap urls = remoteRegistered.get(client); + if (urls != null && urls.size() > 0) { + for (Map.Entry entry : urls.entrySet()) { + super.unregister(entry.getKey(), entry.getValue()); + } + } + Map listeners = remoteListeners.get(client); + if (listeners != null && listeners.size() > 0) { + for (Map.Entry entry : listeners.entrySet()) { + String service = entry.getKey(); + super.unsubscribe(service, getSubscribed(service), entry.getValue()); + } + } + } + + public List getRegistries() { + return registries; + } + + public void setRegistries(List registries) { + this.registries = registries; + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/UrlUtils.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/UrlUtils.java new file mode 100644 index 0000000000..3a6e78e905 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/UrlUtils.java @@ -0,0 +1,334 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.registry.RegistryFactory; + +public class UrlUtils { + + public static URL parseURL(String address, Map defaults) { + if (address == null || address.length() == 0) { + return null; + } + String url; + if (address.indexOf("://") >= 0) { + url = address; + } else { + String[] addresses = Constants.COMMA_SPLIT_PATTERN.split(address); + url = addresses[0]; + if (addresses.length > 1) { + StringBuilder backup = new StringBuilder(); + for (int i = 1; i < addresses.length; i++) { + if (i > 1) { + backup.append(","); + } + backup.append(addresses[i]); + } + url += "?" + Constants.BACKUP_KEY + "=" + backup.toString(); + } + } + String defaultProtocol = defaults == null ? null : defaults.get("protocol"); + if (defaultProtocol == null || defaultProtocol.length() == 0) { + if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) { + defaultProtocol = "remote"; + } else { + defaultProtocol = "dubbo"; + } + } + String defaultUsername = defaults == null ? null : defaults.get("username"); + String defaultPassword = defaults == null ? null : defaults.get("password"); + int defaultPort = StringUtils.parseInteger(defaults == null ? null : defaults.get("port")); + String defaultPath = defaults == null ? null : defaults.get("path"); + Map defaultParameters = defaults == null ? null : new HashMap(defaults); + if (defaultParameters != null) { + defaultParameters.remove("protocol"); + defaultParameters.remove("username"); + defaultParameters.remove("password"); + defaultParameters.remove("host"); + defaultParameters.remove("port"); + defaultParameters.remove("path"); + } + URL u = URL.valueOf(url); + boolean changed = false; + String protocol = u.getProtocol(); + String username = u.getUsername(); + String password = u.getPassword(); + String host = NetUtils.filterLocalHost(u.getHost()); + int port = u.getPort(); + String path = u.getPath(); + Map parameters = new HashMap(u.getParameters()); + if ((protocol == null || protocol.length() == 0) + && defaultProtocol != null && defaultProtocol.length() > 0) { + changed = true; + protocol = defaultProtocol; + } + if ((username == null || username.length() == 0) + && defaultUsername != null && defaultUsername.length() > 0) { + changed = true; + username = defaultUsername; + } + if ((password == null || password.length() == 0) + && defaultPassword != null && defaultPassword.length() > 0) { + changed = true; + password = defaultPassword; + } + if (NetUtils.isInvalidLocalHost(host)) { + changed = true; + host = NetUtils.getLocalHost(); + } + if (port <= 0) { + if (defaultPort > 0) { + changed = true; + port = defaultPort; + } else { + changed = true; + port = 9090; + } + } + if (path == null || path.length() == 0) { + if (defaultPath != null && defaultPath.length() > 0) { + changed = true; + path = defaultPath; + } + } + if (defaultParameters != null && defaultParameters.size() > 0) { + for (Map.Entry entry : defaultParameters.entrySet()) { + String key = entry.getKey(); + String defaultValue = entry.getValue(); + if (defaultValue != null && defaultValue.length() > 0) { + String value = parameters.get(key); + if (value == null || value.length() == 0) { + changed = true; + parameters.put(key, defaultValue); + } + } + } + } + if (changed) { + u = new URL(protocol, username, password, host, port, path, parameters); + } + return u; + } + + public static List parseURLs(String address, Map defaults) { + if (address == null || address.length() == 0) { + return null; + } + String[] addresses = Constants.REGISTRY_SPLIT_PATTERN.split(address); + if (addresses == null || addresses.length == 0) { + return null; + } + List registries = new ArrayList(); + for (String addr : addresses) { + registries.add(parseURL(addr, defaults)); + } + return registries; + } + + public static Map> convertRegister(Map> register) { + Map> newRegister = new HashMap>(); + for (Map.Entry> entry : register.entrySet()) { + String serviceName = entry.getKey(); + Map serviceUrls = entry.getValue(); + if (! serviceName.contains(":") && ! serviceName.contains("/")) { + for (Map.Entry entry2 : serviceUrls.entrySet()) { + String serviceUrl = entry2.getKey(); + String serviceQuery = entry2.getValue(); + Map params = StringUtils.parseQueryString(serviceQuery); + String group = params.get("group"); + String version = params.get("version"); + params.remove("group"); + params.remove("version"); + String name = serviceName; + if (group != null && group.length() > 0) { + name = group + "/" + name; + } + if (version != null && version.length() > 0) { + name = name + ":" + version; + } + Map newUrls = newRegister.get(name); + if (newUrls == null) { + newUrls = new HashMap(); + newRegister.put(name, newUrls); + } + newUrls.put(serviceUrl, StringUtils.toQueryString(params)); + } + } else { + newRegister.put(serviceName, serviceUrls); + } + } + return newRegister; + } + + public static Map convertSubscribe(Map subscribe) { + Map newSubscribe = new HashMap(); + for (Map.Entry entry : subscribe.entrySet()) { + String serviceName = entry.getKey(); + String serviceQuery = entry.getValue(); + if (! serviceName.contains(":") && ! serviceName.contains("/")) { + Map params = StringUtils.parseQueryString(serviceQuery); + String group = params.get("group"); + String version = params.get("version"); + params.remove("group"); + params.remove("version"); + String name = serviceName; + if (group != null && group.length() > 0) { + name = group + "/" + name; + } + if (version != null && version.length() > 0) { + name = name + ":" + version; + } + newSubscribe.put(name, StringUtils.toQueryString(params)); + } else { + newSubscribe.put(serviceName, serviceQuery); + } + } + return newSubscribe; + } + + public static Map> revertRegister(Map> register) { + Map> newRegister = new HashMap>(); + for (Map.Entry> entry : register.entrySet()) { + String serviceName = entry.getKey(); + Map serviceUrls = entry.getValue(); + if (serviceName.contains(":") || serviceName.contains("/")) { + for (Map.Entry entry2 : serviceUrls.entrySet()) { + String serviceUrl = entry2.getKey(); + String serviceQuery = entry2.getValue(); + Map params = StringUtils.parseQueryString(serviceQuery); + String name = serviceName; + int i = name.indexOf('/'); + if (i >= 0) { + params.put("group", name.substring(0, i)); + name = name.substring(i + 1); + } + i = name.lastIndexOf(':'); + if (i >= 0) { + params.put("version", name.substring(i + 1)); + name = name.substring(0, i); + } + Map newUrls = newRegister.get(name); + if (newUrls == null) { + newUrls = new HashMap(); + newRegister.put(name, newUrls); + } + newUrls.put(serviceUrl, StringUtils.toQueryString(params)); + } + } else { + newRegister.put(serviceName, serviceUrls); + } + } + return newRegister; + } + + public static Map revertSubscribe(Map subscribe) { + Map newSubscribe = new HashMap(); + for (Map.Entry entry : subscribe.entrySet()) { + String serviceName = entry.getKey(); + String serviceQuery = entry.getValue(); + if (serviceName.contains(":") || serviceName.contains("/")) { + Map params = StringUtils.parseQueryString(serviceQuery); + String name = serviceName; + int i = name.indexOf('/'); + if (i >= 0) { + params.put("group", name.substring(0, i)); + name = name.substring(i + 1); + } + i = name.lastIndexOf(':'); + if (i >= 0) { + params.put("version", name.substring(i + 1)); + name = name.substring(0, i); + } + newSubscribe.put(name, StringUtils.toQueryString(params)); + } else { + newSubscribe.put(serviceName, serviceQuery); + } + } + return newSubscribe; + } + + public static Map> revertNotify(Map> notify) { + if (notify != null && notify.size() > 0) { + Map> newNotify = new HashMap>(); + for (Map.Entry> entry : notify.entrySet()) { + String serviceName = entry.getKey(); + Map serviceUrls = entry.getValue(); + if (! serviceName.contains(":") && ! serviceName.contains("/")) { + if (serviceUrls != null && serviceUrls.size() > 0) { + for (Map.Entry entry2 : serviceUrls.entrySet()) { + String url = entry2.getKey(); + String query = entry2.getValue(); + Map params = StringUtils.parseQueryString(query); + String group = params.get("group"); + String version = params.get("version"); + //params.remove("group"); + //params.remove("version"); + String name = serviceName; + if (group != null && group.length() > 0) { + name = group + "/" + name; + } + if (version != null && version.length() > 0) { + name = name + ":" + version; + } + Map newUrls = newNotify.get(name); + if (newUrls == null) { + newUrls = new HashMap(); + newNotify.put(name, newUrls); + } + newUrls.put(url, StringUtils.toQueryString(params)); + } + } + } else { + newNotify.put(serviceName, serviceUrls); + } + } + return newNotify; + } + return notify; + } + + public static List revertForbid(List forbid, Set subscribed) { + if (forbid != null && forbid.size() > 0) { + List newForbid = new ArrayList(); + for (String serviceName : forbid) { + if (! serviceName.contains(":") && ! serviceName.contains("/")) { + for (String name : subscribed) { + if (name.contains(serviceName)) { + newForbid.add(name); + break; + } + } + } else { + newForbid.add(serviceName); + } + } + return newForbid; + } + return forbid; + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/dubbo/DubboRegistry.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/dubbo/DubboRegistry.java new file mode 100644 index 0000000000..ca9f17bd04 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/dubbo/DubboRegistry.java @@ -0,0 +1,343 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support.dubbo; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcConstants; + +/** + * DubboRegistry + * + * @author william.liangf + */ +public class DubboRegistry implements Registry { + + private final static Logger logger = LoggerFactory.getLogger(DubboRegistry.class); + + private static final int RETRY_FAILED_PERIOD_DEFAULT = 5 * 1000; + + // 重连检测周期3秒(单位毫秒) + private static final int RECONNECT_PERIOD_DEFAULT = 3 * 1000; + + // 定时任务执行器 + private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2, new NamedThreadFactory("DubboRegistryClientTimer", true)); + + // 失败重试定时器,定时检查是否有请求失败,如有,无限次重试 + private final ScheduledFuture retryFailedFuture; + + // 重连定时器,定时检查连接是否可用,不可用时,无限次重连 + private final ScheduledFuture reconnectFuture; + + // 客户端获取过程锁,锁定客户端实例的创建过程,防止重复的客户端 + private final ReentrantLock clientLock = new ReentrantLock(); + + private final Set registered = new ConcurrentHashSet(); + + private final ConcurrentMap subscribed = new ConcurrentHashMap(); + + // 失败的注册信息,定时重试 + private final Set failedRegistered = new ConcurrentHashSet(); + + private final Set failedUnregistered = new ConcurrentHashSet(); + + // 失败的订阅信息,定时重试 + private final ConcurrentMap failedSubscribed = new ConcurrentHashMap(); + + private final ConcurrentMap failedUnsubscribed = new ConcurrentHashMap(); + + private final Invoker registryInvoker; + + private final RegistryService registryService; + + public DubboRegistry(Invoker registryInvoker, RegistryService registryService) { + this.registryInvoker = registryInvoker; + this.registryService = registryService; + // 启动重连定时器 + int reconnectPeriod = registryInvoker.getUrl().getIntParameter(RpcConstants.REGISTRY_RECONNECT_PERIOD_KEY, RECONNECT_PERIOD_DEFAULT); + reconnectFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + public void run() { + // 检测并连接注册中心 + try { + connect(); + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at reconnect, cause: " + t.getMessage(), t); + } + } + }, reconnectPeriod, reconnectPeriod, TimeUnit.MILLISECONDS); + int retryFailedPeriod = registryInvoker.getUrl().getIntParameter(RpcConstants.REGISTRY_RETRY_FAILED_PERIOD_KEY,RETRY_FAILED_PERIOD_DEFAULT); + this.retryFailedFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + public void run() { + // 检测并连接注册中心 + try { + retryFailed(); + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t); + } + } + }, retryFailedPeriod, retryFailedPeriod, TimeUnit.MILLISECONDS); + } + + protected final void connect() { + try { + // 检查是否已连接 + if (isAvailable()) { + return; + } + if (logger.isInfoEnabled()) { + logger.info("Reconnect to registry " + getUrl()); + } + clientLock.lock(); + try { + // 双重检查是否已连接 + if (isAvailable()) { + return; + } + recover(); + } finally { + clientLock.unlock(); + } + } catch (Throwable t) { // 忽略所有异常,等待下次重试 + if (getUrl().getBooleanParameter(Constants.CHECK_KEY, true)) { + if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } + throw new RuntimeException(t.getMessage(), t); + } + logger.error("Failed to connect to registry " + getUrl().getAddress() + " from provider/consumer " + NetUtils.getLocalHost() + " use dubbo " + Version.getVersion() + ", cause: " + t.getMessage(), t); + } + } + + // 重试失败的动作 + private void retryFailed() throws Exception { + if (! failedRegistered.isEmpty()) { + Set failed = new HashSet(failedRegistered); + if (logger.isInfoEnabled()) { + logger.info("Retry register services " + failed); + } + if (! failed.isEmpty()) { + try { + for (String url : failed) { + registryService.register(URL.valueOf(url)); + failedRegistered.remove(url); + } + } catch (Throwable t) { // 忽略所有异常,等待下次重试 + logger.warn("Failed to retry register services " + failed, t); + } + } + } + if(! failedUnregistered.isEmpty()) { + Set failed = new HashSet(failedUnregistered); + if (logger.isInfoEnabled()) { + logger.info("Retry unregister services " + failed); + } + try { + for (String url : failed) { + registryService.unregister(URL.valueOf(url)); + failedUnregistered.remove(url); + } + } catch (Throwable t) { // 忽略所有异常,等待下次重试 + logger.warn("Failed to retry unregister services " + failed, t); + } + } + if (! failedSubscribed.isEmpty()) { + Map failed = new HashMap(failedSubscribed); + if (logger.isInfoEnabled()) { + logger.info("Retry subscribe services " + failed); + } + try { + for (Map.Entry entry : failed.entrySet()) { + String url = entry.getKey(); + registryService.subscribe(URL.valueOf(url), entry.getValue()); + failedSubscribed.remove(url); + } + } catch (Throwable t) { // 忽略所有异常,等待下次重试 + logger.warn("Failed to retry subscribe services " + failed, t); + } + } + if (! failedUnsubscribed.isEmpty()) { + Map failed = new HashMap(failedUnsubscribed); + if (logger.isInfoEnabled()) { + logger.info("Retry unsubscribe services " + failed); + } + try { + for (Map.Entry entry : failed.entrySet()) { + String url = entry.getKey(); + registryService.unsubscribe(URL.valueOf(url), entry.getValue()); + failedSubscribed.remove(url); + } + } catch (Throwable t) { // 忽略所有异常,等待下次重试 + logger.warn("Failed to retry unsubscribe services " + failed, t); + } + } + } + + protected final void recover() throws Exception { + // register + Set recoverRegistered = new HashSet(registered); + if (! recoverRegistered.isEmpty()) { + if (logger.isInfoEnabled()) { + logger.info("Recover register services " + recoverRegistered); + } + for (String url : recoverRegistered) { + register(URL.valueOf(url)); + } + } + // subscribe + Map recoverSubscribed = new HashMap(subscribed); + if (recoverSubscribed.size() > 0) { + if (logger.isInfoEnabled()) { + logger.info("Recover subscribe services " + recoverSubscribed); + } + for (Map.Entry entry : recoverSubscribed.entrySet()) { + String url = entry.getKey(); + subscribe(URL.valueOf(url), entry.getValue()); + } + } + } + + public boolean isAvailable() { + if (registryInvoker == null) + return false; + return registryInvoker.isAvailable(); + } + + public URL getUrl() { + return registryInvoker.getUrl(); + } + + public void destroy() { + if (logger.isInfoEnabled()){ + logger.info("Destroy registry: " + getUrl()); + } + try { + // 取消失败重试定时器 + if (! retryFailedFuture.isCancelled()) { + retryFailedFuture.cancel(true); + } + } catch (Throwable t) { + logger.warn("Failed to cancel retry timer", t); + } + try { + // 取消重连定时器 + if (! reconnectFuture.isCancelled()) { + reconnectFuture.cancel(true); + } + } catch (Throwable t) { + logger.warn("Failed to cancel reconnect timer", t); + } + registryInvoker.destroy(); + } + + public List lookup(URL url) { + if (logger.isInfoEnabled()){ + logger.info("Lookup: " + url); + } + return registryService.lookup(url); + } + + public void register(URL url) { + if (logger.isInfoEnabled()){ + logger.info("Register: " + url); + } + try { + registryService.register(url); + registered.add(url.toFullString()); + } catch (Exception t) { + if (getUrl().getBooleanParameter(Constants.CHECK_KEY, true)) { + throw new IllegalStateException("Failed to register " + url + ", cause: " + t.getMessage(), t); + } + // 记录失败,定时重试 + failedRegistered.add(url.toFullString()); + logger.error("Failed to register " + url + ", cause: " + t.getMessage(), t); + } + } + + public void unregister(URL url) { + if (logger.isInfoEnabled()){ + logger.info("Unregister: " + url); + } + try { + registryService.unregister(url); + registered.remove(url.toFullString()); + } catch (Exception t) { + if (getUrl().getBooleanParameter(Constants.CHECK_KEY, true)) { + throw new IllegalStateException("Failed to unregister " + url + ", cause: " + t.getMessage(), t); + } + // 记录失败,定时重试 + failedUnregistered.add(url.toFullString()); + logger.error("Failed to unregister " + url + ", cause: " + t.getMessage(), t); + } + } + + public void subscribe(URL url, NotifyListener listener) { + if (logger.isInfoEnabled()){ + logger.info("Subscribe: " + url); + } + try { + registryService.subscribe(url, listener); + subscribed.put(url.toFullString(), listener); + } catch (Exception t) { + if (getUrl().getBooleanParameter(Constants.CHECK_KEY, true)) { + throw new IllegalStateException("Failed to subscribe " + url + ", cause: " + t.getMessage(), t); + } + // 记录失败,定时重试 + failedSubscribed.put(url.toFullString(), listener); + logger.error("Failed to subscribe " + url + ", cause: " + t.getMessage(), t); + } + } + + public void unsubscribe(URL url, NotifyListener listener) { + if (logger.isInfoEnabled()){ + logger.info("Unsubscribe: " + url); + } + try { + registryService.unsubscribe(url, listener); + subscribed.remove(url.toFullString()); + } catch (Exception t) { + if (getUrl().getBooleanParameter(Constants.CHECK_KEY, true)) { + throw new IllegalStateException("Failed to unsubscribe " + url + ", cause: " + t.getMessage(), t); + } + // 记录失败,定时重试 + failedUnsubscribed.put(url.toFullString(), listener); + logger.error("Failed to unsubscribe " + url + ", cause: " + t.getMessage(), t); + } + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/dubbo/DubboRegistryFactory.java b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/dubbo/DubboRegistryFactory.java new file mode 100644 index 0000000000..cef37435d8 --- /dev/null +++ b/dubbo-registry/src/main/java/com/alibaba/dubbo/registry/support/dubbo/DubboRegistryFactory.java @@ -0,0 +1,103 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.support.dubbo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryService; +import com.alibaba.dubbo.registry.directory.RegistryDirectory; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.cluster.Cluster; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +/** + * DubboRegistryFactory + * + * @author william.liangf + */ +@Extension("dubbo") +public class DubboRegistryFactory extends AbstractRegistryFactory { + + private Protocol protocol; + + public void setProtocol(Protocol protocol) { + this.protocol = protocol; + } + + private ProxyFactory proxyFactory; + + public void setProxyFactory(ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + } + + private Cluster cluster; + + public void setCluster(Cluster cluster) { + this.cluster = cluster; + } + + public Registry createRegistry(URL url) { + url = getRegistryURL(url); + List urls = new ArrayList(); + urls.add(url.removeParameter(Constants.BACKUP_KEY)); + String backup = url.getParameter(Constants.BACKUP_KEY); + if (backup != null && backup.length() > 0) { + String[] addresses = Constants.COMMA_SPLIT_PATTERN.split(backup); + for (String address : addresses) { + urls.add(url.setAddress(address)); + } + } + RegistryDirectory directory = new RegistryDirectory(RegistryService.class, url.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName()).addParameterAndEncoded(RpcConstants.REFER_KEY, url.toParameterString())); + Invoker registryInvoker = cluster.merge(directory); + RegistryService registryService = proxyFactory.getProxy(registryInvoker); + DubboRegistry registry = new DubboRegistry(registryInvoker, registryService); + directory.setRegistry(registry); + directory.setProtocol(protocol); + directory.notify(urls); + registryService.subscribe(url, directory); + return registry; + } + + private static URL getRegistryURL(URL url) { + return url.setPath(RegistryService.class.getName()) + .removeParameter(RpcConstants.EXPORT_KEY).removeParameter(RpcConstants.REFER_KEY) + .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName()) + .addParameter(RpcConstants.CLUSTER_STICKY_KEY, "true") + .addParameter(RpcConstants.LAZY_CONNECT_KEY, "true") + .addParameter(Constants.RECONNECT_KEY, "false") + .addParameterIfAbsent(Constants.TIMEOUT_KEY, "10000") + .addParameterIfAbsent(RpcConstants.CALLBACK_INSTANCES_LIMIT_KEY, "10000") + .addParameterIfAbsent(Constants.CONNECT_TIMEOUT_KEY, "10000") + .addParameter(Constants.METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(Wrapper.getWrapper(RegistryService.class).getDeclaredMethodNames())), ",")) + //.addParameter(Constants.STUB_KEY, RegistryServiceStub.class.getName()) + //.addParameter(RpcConstants.STUB_EVENT_KEY, Boolean.TRUE.toString()) //for event dispatch + //.addParameter(RpcConstants.ON_DISCONNECT_KEY, "disconnect") + .addParameter("subscribe.1.callback", "true") + .addParameter("unsubscribe.1.callback", "false"); + } +} \ No newline at end of file diff --git a/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker b/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker new file mode 100644 index 0000000000..aa8a2a0988 --- /dev/null +++ b/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker @@ -0,0 +1 @@ +com.alibaba.dubbo.registry.status.RegistryStatusChecker \ No newline at end of file diff --git a/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.registry.RegistryFactory b/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.registry.RegistryFactory new file mode 100644 index 0000000000..f7cbccb8bb --- /dev/null +++ b/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +com.alibaba.dubbo.registry.support.dubbo.DubboRegistryFactory \ No newline at end of file diff --git a/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol b/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol new file mode 100644 index 0000000000..bf0b13a669 --- /dev/null +++ b/dubbo-registry/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol @@ -0,0 +1 @@ +com.alibaba.dubbo.registry.protocol.RegistryProtocol \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/MockChannel.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/MockChannel.java new file mode 100644 index 0000000000..6b3271c742 --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/MockChannel.java @@ -0,0 +1,111 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; + +public class MockChannel implements ExchangeChannel { + + final InetSocketAddress localAddress; + + final InetSocketAddress remoteAddress; + + public static boolean closed = false; + + public MockChannel(String localHostname, int localPort, String remoteHostName, int remotePort){ + localAddress = new InetSocketAddress(localHostname, localPort); + remoteAddress = new InetSocketAddress(remoteHostName, remotePort); + closed = false; + } + + public InetSocketAddress getLocalAddress() { + return localAddress; + } + + public InetSocketAddress getRemoteAddress() { + return remoteAddress; + } + + public boolean isConnected() { + return true; + } + + public void close() { + closed = true; + } + + public void send(Object message) throws RemotingException { + } + + public void close(int timeout) { + } + + public URL getUrl() { + return null; + } + + public ResponseFuture send(Object request, int timeout) throws RemotingException { + return null; + } + + public ChannelHandler getChannelHandler() { + return null; + } + + public ResponseFuture request(Object request) throws RemotingException { + return null; + } + + public ResponseFuture request(Object request, int timeout) throws RemotingException { + return null; + } + + public ExchangeHandler getExchangeHandler() { + return null; + } + + public Object getAttribute(String key) { + return null; + } + + public void setAttribute(String key, Object value) { + + } + + public boolean hasAttribute(String key) { + return false; + } + + public boolean isClosed() { + return false; + } + + public void removeAttribute(String key) { + + } + + public void send(Object message, boolean sent) throws RemotingException { + + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/MockedClient.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/MockedClient.java new file mode 100644 index 0000000000..72bddacdaf --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/MockedClient.java @@ -0,0 +1,259 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import java.net.InetSocketAddress; +import java.util.Map; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.ResponseCallback; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.remoting.exchange.support.Replier; + +/** + * MockedClient + * + * @author william.liangf + */ +public class MockedClient implements ExchangeClient { + + //private String host; + + //private int port; + + private boolean connected; + + private Object received; + + private Object sent; + + private Object invoked; + + private Replier handler; + + private InetSocketAddress address; + + private boolean closed = false; + + //private ChannelListener listener; + + public MockedClient(String host, int port, boolean connected) { + this(host, port, connected, null); + } + + public MockedClient(String host, int port, boolean connected, Object received) { + this.address = new InetSocketAddress(host, port); + this.connected = connected; + this.received = received; + } + + public void open() { + } + + public void close() { + this.closed = true; + } + + public void send(Object msg) throws RemotingException { + this.sent = msg; + } + + public ResponseFuture request(Object msg) throws RemotingException { + return request(msg, 0); + } + + public ResponseFuture request(Object msg, int timeout) throws RemotingException { + this.invoked = msg; + return new ResponseFuture() { + public Object get() throws RemotingException { + return received; + } + public Object get(int timeoutInMillis) throws RemotingException { + return received; + } + public boolean isDone() { + return true; + } + public void setCallback(ResponseCallback callback) { + } + }; + } + + public void registerHandler(Replier handler) { + this.handler = handler; + } + + public void unregisterHandler(Replier handler) { + //this.handler = null; + } + + public void addChannelListener(ChannelHandler listener) { + //this.listener = listener; + } + + public void removeChannelListener(ChannelHandler listener) { + //this.listener = null; + } + + public boolean isConnected() { + return connected; + } + + public Object getSent() { + return sent; + } + + public Replier getHandler() { + return handler; + } + + public Object getInvoked() { + return invoked; + } + + public InetSocketAddress getRemoteAddress() { + return address; + } + + public String getName() { + return "mocked"; + } + + public InetSocketAddress getLocalAddress() { + return null; + } + + public void setTimeout(int timeout) { + } + + public int getTimeout() { + return 0; + } + + public void close(int timeout) { + } + + public boolean isOpen() { + return false; + } + + public Codec getCodec() { + return null; + } + + public void setCodec(Codec codec) { + } + + public void setHost(String host) { + } + + public String getHost() { + return null; + } + + public void setPort(int port) { + } + + public int getPort() { + return 0; + } + + public void setThreadCount(int threadCount) { + } + + public int getThreadCount() { + return 0; + } + + public URL getUrl() { + return null; + } + + public Replier getReceiver() { + return null; + } + + public ChannelHandler getChannelHandler() { + return null; + } + + public void reset(Map parameters) { + } + + public Channel getChannel() { + return this; + } + + public ExchangeHandler getExchangeHandler() { + return null; + } + + public void reconnect() throws RemotingException { + } + + public Object getAttribute(String key) { + return null; + } + + public void setAttribute(String key, Object value) { + + } + + public boolean hasAttribute(String key) { + return false; + } + + public boolean isClosed() { + return closed; + } + + public void removeAttribute(String key) { + + } + /** + * @return the received + */ + public Object getReceived() { + return received; + } + + /** + * @param received the received to set + */ + public void setReceived(Object received) { + this.received = received; + } + + /** + * @param connected the connected to set + */ + public void setConnected(boolean connected) { + this.connected = connected; + } + + public void send(Object message, boolean sent) throws RemotingException { + } + + public void reset(URL url) { + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/PerformanceRegistryTest.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/PerformanceRegistryTest.java new file mode 100644 index 0000000000..832aaa5445 --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/PerformanceRegistryTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; + +/** + * RegistryPerformanceTest + * + * @author william.liangf + */ +public class PerformanceRegistryTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceRegistryTest.class); + + @Test + public void testRegistry() { + // 读取参数 + if (PerformanceUtils.getProperty("server", null) == null) { + logger.warn("Please set -Dserver=127.0.0.1:9090"); + return; + } + final int base = PerformanceUtils.getIntProperty("base", 0); + final int concurrent = PerformanceUtils.getIntProperty("concurrent", 100); + int r = PerformanceUtils.getIntProperty("runs", 1000); + final int runs = r > 0 ? r : Integer.MAX_VALUE; + final Registry registry = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension().getRegistry(URL.valueOf("remote://admin:hello1234@" + PerformanceUtils.getProperty("server", "10.20.153.28:9090"))); + for (int i = 0; i < concurrent; i ++) { + final int t = i; + new Thread(new Runnable() { + public void run() { + for (int j = 0; j < runs; j ++) { + registry.register(URL.valueOf("remote://" + NetUtils.getLocalHost() + ":8080/demoService" + t + "_" + j + "?version=1.0.0&application=demo&dubbo=2.0&interface=" + "com.alibaba.dubbo.demo.DemoService" + (base + t) + "_" + (base + j))); + } + } + }).start(); + } + synchronized (PerformanceRegistryTest.class) { + while (true) { + try { + PerformanceRegistryTest.class.wait(); + } catch (InterruptedException e) { + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/PerformanceUtils.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/PerformanceUtils.java new file mode 100644 index 0000000000..1e6683c9b9 --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/PerformanceUtils.java @@ -0,0 +1,126 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + +import java.net.NetworkInterface; +import java.net.SocketException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * PerformanceUtils + * + * @author william.liangf + */ +public class PerformanceUtils { + + public static String getProperty(String key, String defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return value.trim(); + } + + public static int getIntProperty(String key, int defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return Integer.parseInt(value.trim()); + } + public static boolean getBooleanProperty(String key, boolean defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return Boolean.parseBoolean(value.trim()); + } + + public static List getEnvironment() { + List environment = new ArrayList(); + environment.add("OS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch", "")); + environment.add("CPU: " + Runtime.getRuntime().availableProcessors() + " cores"); + environment.add("JVM: " + System.getProperty("java.vm.name") + " " + System.getProperty("java.runtime.version")); + environment.add("Memory: " + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().totalMemory()) + + " bytes (Max: " + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().maxMemory()) + " bytes)"); + NetworkInterface ni = PerformanceUtils.getNetworkInterface(); + if (ni != null) { + environment.add("Network: " + ni.getDisplayName()); + } + return environment; + } + + private static final int WIDTH = 64; + + public static void printSeparator() { + StringBuilder pad = new StringBuilder(); + for (int i = 0; i < WIDTH; i ++) { + pad.append("-"); + } + System.out.println("+" + pad + "+"); + } + + public static void printBorder() { + StringBuilder pad = new StringBuilder(); + for (int i = 0; i < WIDTH; i ++) { + pad.append("="); + } + System.out.println("+" + pad + "+"); + } + + public static void printBody(String msg) { + StringBuilder pad = new StringBuilder(); + int len = WIDTH - msg.length() - 1; + if (len > 0) { + for (int i = 0; i < len; i ++) { + pad.append(" "); + } + } + System.out.println("| " + msg + pad + "|"); + } + + public static void printHeader(String msg) { + StringBuilder pad = new StringBuilder(); + int len = WIDTH - msg.length(); + if (len > 0) { + int half = len / 2; + for (int i = 0; i < half; i ++) { + pad.append(" "); + } + } + System.out.println("|" + pad + msg + pad + ((len % 2 == 0) ? "" : " ") + "|"); + } + + public static NetworkInterface getNetworkInterface() { + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (interfaces != null) { + while (interfaces.hasMoreElements()) { + try { + return interfaces.nextElement(); + } catch (Throwable e) { + } + } + } + } catch (SocketException e) { + } + return null; + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/RegistryTestSupport.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/RegistryTestSupport.java new file mode 100644 index 0000000000..9a107df68d --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/RegistryTestSupport.java @@ -0,0 +1,215 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry; + + +/** + * @author ding.lid + */ +public class RegistryTestSupport { + /*public static void assertEqualsIgnoreOrde(Collection expected, Collection actual) { + Set expectedSet; + if (expected instanceof Set) { + expectedSet = (Set) expected; + } else { + expectedSet = new HashSet(expected); + } + + Set actualSet; + if (actual instanceof Set) { + actualSet = (Set) actual; + } else { + actualSet = new HashSet(actual); + } + + Assert.assertEquals(expectedSet, actualSet); + } + + public static final String member_service_name = "com.alibaba.morgan.MemberService"; + + public static final Map member_urls1; + static { + Map m = new HashMap(); + m.put("remote://10.20.130.230:9090/memberService", "version=1.0.0"); + + member_urls1 = Collections.unmodifiableMap(m); + } + + public static final Map member_urls2; + static { + Map m = new HashMap(); + m.put("remote://11.11.11.11:9090/memberService", "version=1.0.0"); + m.put("remote://22.22.22.22:9090/memberService", "version=1.0.0"); + m.put("remote://33.33.33.33:9090/memberService", "version=1.0.0"); + + member_urls2 = Collections.unmodifiableMap(m); + } + + public static final Map member_urls3; + static { + Map m = new HashMap(); + m.put("remote://44.44.44.44:9090/memberService", "version=1.0.0"); + member_urls3 = Collections.unmodifiableMap(m); + } + + public static final String xxx_service_name = "com.alibaba.xxx.XxxService"; + + public static final Map xxx_urls1; + static { + Map m = new HashMap(); + m.put("remote://11.11.11.11:9090/xxxService", "version=1.0.0"); + m.put("remote://22.22.22.22:9090/xxxService", "version=1.0.0"); + + xxx_urls1 = Collections.unmodifiableMap(m); + } + + public static void registerCheck(AbstractRegistry registry) { + { + List registeredList = registry + .getRegistered("com.alibaba.morgan.MemberService"); + assertEquals(0, registeredList.size()); + + Map> registeredMap = registry.getRegistered(); + assertEquals(0, registeredMap.size()); + } + + { + for (Map.Entry entry : member_urls1.entrySet()) { + registry.register(member_service_name, entry.getKey(), entry.getValue()); + } + + Map registered = registry.getRegistered(member_service_name); + assertEquals(1, registered.size()); + assertNotSame(member_urls1, registered); + assertEquals(member_urls1, registered); + + Map> registeredMap = registry.getRegistered(); + assertEquals(1, registeredMap.size()); + assertTrue(registeredMap.containsKey(member_service_name)); + + registered = registeredMap.get(member_service_name); + assertEquals(1, registered.size()); + assertNotSame(member_urls1, registered); + assertEquals(member_urls1, registered); + } + + { + registry.register(member_service_name, member_urls2); + + Map registered = registry.getRegistered(member_service_name); + + final Map urls = new HashMap(); + urls.putAll(member_urls1); + urls.putAll(member_urls2); + + assertEquals(urls, registered); + + Map> registeredMap = registry.getRegistered(); + assertEquals(1, registeredMap.size()); + assertTrue(registeredMap.containsKey(member_service_name)); + + registered = registeredMap.get(member_service_name); + assertEquals(urls, registered); + } + + { + Map> services = new HashMap>(); + services.put(member_service_name, member_urls3); + services.put(xxx_service_name, xxx_urls1); + + registry.register(services); + + final Map urls = new HashMap(); + urls.putAll(member_urls1); + urls.putAll(member_urls2); + urls.putAll(member_urls3); + { + Map registered = registry.getRegistered(member_service_name); + assertEquals(urls, registered); + + registered = registry.getRegistered(xxx_service_name); + assertEquals(xxx_urls1, registered); + } + + { + Map> registeredMap = registry.getRegistered(); + assertEquals(2, registeredMap.size()); + assertTrue(registeredMap.containsKey(member_service_name)); + assertTrue(registeredMap.containsKey(xxx_service_name)); + + Map registered = registeredMap.get(member_service_name); + assertEquals(urls, registered); + + registered = registeredMap.get(xxx_service_name); + assertEquals(xxx_urls1, registered); + } + } + } + + public static void subscribeCheck(AbstractRegistry registry, NotificationListener mockNotifyListener) { + String subscribed = registry.getSubscribed("com.alibaba.morgan.MemberService"); + assertNull(subscribed); + + Map subscribedMap = registry.getSubscribed(); + assertEquals(0, subscribedMap.size()); + + // query允许为null + registry.subscribe("com.alibaba.xxx.XxxService", (String) null, mockNotifyListener); + + subscribed = registry.getSubscribed("com.alibaba.xxx.XxxService"); + assertEquals("", subscribed); + + subscribedMap = registry.getSubscribed(); + assertEquals(1, subscribedMap.size()); + assertTrue(subscribedMap.containsKey("com.alibaba.xxx.XxxService")); + assertEquals("", subscribedMap.get("com.alibaba.xxx.XxxService")); + + registry.subscribe("com.alibaba.empty.EmptyService", "", mockNotifyListener); + + // query允许为空 + subscribed = registry.getSubscribed("com.alibaba.empty.EmptyService"); + assertEquals("", subscribed); + + subscribedMap = registry.getSubscribed(); + assertEquals(2, subscribedMap.size()); + assertTrue(subscribedMap.containsKey("com.alibaba.empty.EmptyService")); + assertEquals("", subscribedMap.get("com.alibaba.empty.EmptyService")); + + // 多项值的Query + registry.subscribe("com.alibaba.morgan.MemberService", "dog=bad,cat=god", + mockNotifyListener); + + subscribed = registry.getSubscribed("com.alibaba.morgan.MemberService"); + assertEquals("dog=bad,cat=god", subscribed); + + subscribedMap = registry.getSubscribed(); + assertEquals(3, subscribedMap.size()); + String s = subscribedMap.get("com.alibaba.morgan.MemberService"); + assertEquals("dog=bad,cat=god", s); + + registry.subscribe("com.alibaba.complex.ComplexService", + "version=1.0.0&application=kylin&methods=findPerson,findVAccount", + mockNotifyListener); + + subscribedMap = registry.getSubscribed(); + assertEquals(4, subscribedMap.size()); + String q = subscribedMap.get("com.alibaba.complex.ComplexService"); + assertEquals("version=1.0.0&application=kylin&methods=findPerson,findVAccount", q); + }*/ + + public void testDummy() { + } +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/directory/RegistryDirectoryTest.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/directory/RegistryDirectoryTest.java new file mode 100644 index 0000000000..5a0b3bc14f --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/directory/RegistryDirectoryTest.java @@ -0,0 +1,395 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.directory; + +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.support.SimpleRegistryExporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.cluster.Router; +import com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance; +import com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance; +import com.alibaba.dubbo.rpc.cluster.router.ScriptRouter; +import com.alibaba.dubbo.rpc.cluster.router.ScriptRouterFactory; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class RegistryDirectoryTest { + private static String service = "com.alibaba.dubbo.demo.DemoService"; + static { + SimpleRegistryExporter.exportIfAbsent(9090); + SimpleRegistryExporter.exportIfAbsent(9091); + SimpleRegistryExporter.exportIfAbsent(9092); + SimpleRegistryExporter.exportIfAbsent(9093); + } + public static URL REGURL= URL.valueOf("dubbo://0.0.0.0:9090/"+service + "?callbacks=100"); + public static URL SERVICEURL= URL.valueOf("dubbo://0.0.0.0:9091/"+service + "?callbacks=100"); + public static URL SERVICEURL2= URL.valueOf("dubbo://0.0.0.0:9092/"+service + "?callbacks=100"); + public static URL SERVICEURL3= URL.valueOf("dubbo://0.0.0.0:9093/"+service + "?callbacks=100"); + public static URL SERVICEURL_DUBBO_NOPATH= URL.valueOf("dubbo://0.0.0.0:9092" + "?callbacks=100"); + + public static URL ROUTERURL= URL.valueOf(RpcConstants.ROUTE_PROTOCOL + "://0.0.0.0:9096/"); + public static URL ROUTERURL2= URL.valueOf(RpcConstants.ROUTE_PROTOCOL + "://0.0.0.0:9097/"); + + + List invokers = null; + RpcInvocation invocation = new RpcInvocation(); + RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = REGURL.addParameter("test", "reg"); + RegistryDirectory registryDirectory = new RegistryDirectory(RegistryDirectoryTest.class, url); + { + registryDirectory.setRegistry(registryFactory.getRegistry(url)); + registryDirectory.setProtocol(protocol); + } + URL url2 = REGURL.addParameter("test", "reg").addParameterAndEncoded(RpcConstants.REFER_KEY, + "key=query&" + Constants.LOADBALANCE_KEY + "=" + LeastActiveLoadBalance.NAME); + RegistryDirectory registryDirectory2 = new RegistryDirectory(RegistryDirectoryTest.class, url2); + { + registryDirectory2.setRegistry(registryFactory.getRegistry(url2)); + registryDirectory2.setProtocol(protocol); + } + + @Test + public void testNotified() { + + invokers = registryDirectory.list(invocation); + Assert.assertEquals(0,invokers.size()); + + test2invokers(); + test1invokers(); + test3invokers(); + testforbid(); + + } + //forbid + private void testforbid(){ + invocation = new RpcInvocation(); + List serviceUrls = new ArrayList (); + registryDirectory.notify(serviceUrls); + try { + invokers = registryDirectory.list(invocation); + fail("forbid must throw RpcException"); + } catch (RpcException e) { + Assert.assertEquals(RpcException.FORBIDDEN_EXCEPTION, e.getCode()); + } + } + + //通知成一个invoker=================================== + private void test1invokers(){ + + List serviceUrls = new ArrayList (); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));//.addParameter("refer.autodestroy", "true") + registryDirectory.notify(serviceUrls); + + invocation = new RpcInvocation(); + + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1,invokers.size()); + + invocation.setMethodName("getXXX"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1,invokers.size()); + + invocation.setMethodName("getXXX1"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1,invokers.size()); + + invocation.setMethodName("getXXX2"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1,invokers.size()); + } + + //两个invoker=================================== + private void test2invokers(){ + List serviceUrls = new ArrayList (); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1")); + serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2")); + serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2")); + + registryDirectory.notify(serviceUrls); + + + invocation = new RpcInvocation(); + + invokers = registryDirectory.list(invocation); + Assert.assertEquals(2,invokers.size()); + + invocation.setMethodName("getXXX"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(2,invokers.size()); + + invocation.setMethodName("getXXX1"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(2,invokers.size()); + + invocation.setMethodName("getXXX2"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1,invokers.size()); + } + + //通知成3个invoker=================================== + private void test3invokers(){ + List serviceUrls = new ArrayList (); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1")); + serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2")); + serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1,getXXX2,getXXX3")); + + registryDirectory.notify(serviceUrls); + + invocation = new RpcInvocation(); + + invokers = registryDirectory.list(invocation); + Assert.assertEquals(3,invokers.size()); + + + invocation.setMethodName("getXXX"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(3,invokers.size()); + + invocation.setMethodName("getXXX1"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(3,invokers.size()); + + invocation.setMethodName("getXXX2"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(2,invokers.size()); + + invocation.setMethodName("getXXX3"); + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1,invokers.size()); + } + + @Test + public void testParametersMerge(){ + + List serviceUrls = new ArrayList (); + //检验注册中心的参数需要被清除 + { + serviceUrls.clear(); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1")); + registryDirectory.notify(serviceUrls); + + invocation = new RpcInvocation(); + invokers = registryDirectory.list(invocation); + + Invoker invoker = (Invoker) invokers.get(0); + URL url = invoker.getUrl(); + Assert.assertEquals(null, url.getParameter("key")); + } + //检验服务提供方的参数需要merge + { + serviceUrls.clear(); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX2").addParameter("key", "provider")); + + registryDirectory.notify(serviceUrls); + invocation = new RpcInvocation(); + invokers = registryDirectory.list(invocation); + + Invoker invoker = (Invoker) invokers.get(0); + URL url = invoker.getUrl(); + Assert.assertEquals("provider",url.getParameter("key")); + } + //检验服务query的参数需要与providermerge 。 + { + serviceUrls.clear(); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX3").addParameter("key", "provider")); + + registryDirectory2.notify(serviceUrls); + invocation = new RpcInvocation(); + invokers = registryDirectory2.list(invocation); + + Invoker invoker = (Invoker) invokers.get(0); + URL url = invoker.getUrl(); + System.out.println(url); + Assert.assertEquals("query",url.getParameter("key")); + } + + { + serviceUrls.clear(); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1")); + registryDirectory.notify(serviceUrls); + + invocation = new RpcInvocation(); + invokers = registryDirectory.list(invocation); + + Invoker invoker = (Invoker) invokers.get(0); + URL url = invoker.getUrl(); + Assert.assertEquals(false,url.getBooleanParameter(Constants.CHECK_KEY)); + } + { + serviceUrls.clear(); + serviceUrls.add(SERVICEURL.addParameter(Constants.LOADBALANCE_KEY, RoundRobinLoadBalance.NAME)); + registryDirectory2.notify(serviceUrls); + + invocation = new RpcInvocation(); + invocation.setMethodName("get"); + invokers = registryDirectory2.list(invocation); + + Invoker invoker = (Invoker) invokers.get(0); + URL url = invoker.getUrl(); + Assert.assertEquals(LeastActiveLoadBalance.NAME,url.getMethodParameter("get",Constants.LOADBALANCE_KEY)); + } + } + + /** + * When destroying, RegistryDirectory should: + * 1. be disconnected from Registry + * 2. destroy all invokers + */ + @Test + public void testDestroy(){ + List serviceUrls = new ArrayList (); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1")); + serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2")); + serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1,getXXX2,getXXX3")); + + registryDirectory.notify(serviceUrls); + registryDirectory.destroy(); + Map>> methodInvokerMap = registryDirectory.getMethodInvokerMap(); + Map> urlInvokerMap = registryDirectory.getUrlInvokerMap(); + + Assert.assertTrue(methodInvokerMap == null); + Assert.assertEquals(0, urlInvokerMap.size()); + //List urls = mockRegistry.getSubscribedUrls(); + + RpcInvocation inv = new RpcInvocation(); + invokers = registryDirectory.list(inv); + Assert.assertEquals(0, invokers.size()); + } + + @Test + public void testDubbo1UrlWithGenericInvocation(){ + + List serviceUrls = new ArrayList (); + serviceUrls.add(SERVICEURL_DUBBO_NOPATH.addParameter("methods", "getXXX1,getXXX2,getXXX3")); + + registryDirectory.notify(serviceUrls); + + //Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException; + invocation = new RpcInvocation(Constants.$INVOKE, + new Class[]{String.class, String[].class, Object[].class}, + new Object[]{"getXXX1", "", new Object[]{}}); + + invokers = registryDirectory.list(invocation); + + Assert.assertEquals(1, invokers.size()); + Assert.assertEquals("dubbo://0.0.0.0:9092/com.alibaba.dubbo.demo.DemoService?callbacks=100&check=false&methods=getXXX1,getXXX2,getXXX3", invokers.get(0).toString()); + + } + + enum Param{ + MORGAN, + }; + + /** + * When the first arg of a method is String or Enum, Registry server + * can do parameter-value-based routing. + */ + @Test + public void testParmeterRoute(){ + List serviceUrls = new ArrayList (); + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1.napoli")); + serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1.MORGAN,getXXX2")); + serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1.morgan,getXXX2,getXXX3")); + + registryDirectory.notify(serviceUrls); + + invocation = new RpcInvocation(Constants.$INVOKE, + new Class[]{String.class, String[].class, Object[].class}, + new Object[]{"getXXX1", new String[]{"Enum"}, new Object[]{Param.MORGAN}}); + + invokers = registryDirectory.list(invocation); + Assert.assertEquals(1, invokers.size()); + } + + /** + * Empty notify cause forbidden, non-empty notify cancels forbidden state + */ + @Test + public void testEmptyNotifyCauseForbidden(){ + invokers = null; + + List serviceUrls = new ArrayList (); + registryDirectory.notify(serviceUrls); + + RpcInvocation inv = new RpcInvocation(); + try{ + invokers = registryDirectory.list(inv); + }catch(RpcException e){ + Assert.assertEquals(RpcException.FORBIDDEN_EXCEPTION, e.getCode()); + } + + serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1")); + serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2")); + serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1,getXXX2,getXXX3")); + + registryDirectory.notify(serviceUrls); + inv.setMethodName("getXXX2"); + invokers = registryDirectory.list(inv); + + Assert.assertEquals(2, invokers.size()); + } + + /** + * 1. notify twice, the second time notified router rules should completely replace the former one. + * 2. notify with no router url, do nothing to current routers + * 3. notify with only one router url, with router=clean, clear all current routers + */ + @Test + public void testNotifyRouterUrls(){ + + List serviceUrls = new ArrayList (); + // without ROUTER_KEY, the first router should not be created. + serviceUrls.add(ROUTERURL.addParameter(RpcConstants.TYPE_KEY, "javascript") + .addParameter(RpcConstants.RULE_KEY, "function test1(){}")); + serviceUrls.add(ROUTERURL2.addParameter(RpcConstants.TYPE_KEY, "javascript") + .addParameter(RpcConstants.ROUTER_KEY, ScriptRouterFactory.NAME) + .addParameter(RpcConstants.RULE_KEY, "function test1(){}")); + + registryDirectory.notify(serviceUrls); + List routers = registryDirectory.getRouters(); + Assert.assertEquals(1, routers.size()); + Assert.assertEquals(ScriptRouter.class, routers.get(0).getClass()); + + registryDirectory.notify(new ArrayList()); + routers = registryDirectory.getRouters(); + Assert.assertEquals(1, routers.size()); + Assert.assertEquals(ScriptRouter.class, routers.get(0).getClass()); + + serviceUrls.clear(); + serviceUrls.add(ROUTERURL.addParameter(RpcConstants.ROUTER_KEY, RpcConstants.ROUTER_TYPE_CLEAR)); + registryDirectory.notify(serviceUrls); + routers = registryDirectory.getRouters(); + Assert.assertEquals(0, routers.size()); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/protocol/DemoService.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/protocol/DemoService.java new file mode 100644 index 0000000000..28f7433a9b --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/protocol/DemoService.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.protocol; + +/** + * TestService + */ + +public interface DemoService +{ + void sayHello(String name); + + int plus(int a,int b); +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/protocol/RegistryProtocolTest.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/protocol/RegistryProtocolTest.java new file mode 100644 index 0000000000..e410aed56e --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/protocol/RegistryProtocolTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.protocol; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.MockedClient; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.support.SimpleRegistryExporter; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.cluster.support.FailfastCluster; +import com.alibaba.dubbo.rpc.dubbo.DubboInvoker; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * RegistryProtocolTest + * + * @author tony.chenl + */ +public class RegistryProtocolTest { + + static { + SimpleRegistryExporter.exportIfAbsent(9090); + } + + String service = "com.alibaba.dubbo.registry.protocol.DemoService:1.0.0"; + String serviceUrl = "dubbo://127.0.0.1:9453/" + service + "?notify=true&methods=test1,test2"; + URL registryUrl = URL.valueOf("dubbo://127.0.0.1:9090/"); + + @Test + public void testDefaultPort() { + RegistryProtocol registryProtocol = new RegistryProtocol(); + assertEquals(9090, registryProtocol.getDefaultPort()); + } + + @Test(expected = IllegalArgumentException.class) + public void testExportUrlNull() { + RegistryProtocol registryProtocol = new RegistryProtocol(); + registryProtocol.setCluster(new FailfastCluster()); + + Protocol dubboProtocol = new DubboProtocol(); + registryProtocol.setProtocol(dubboProtocol); + Invoker invoker = new DubboInvoker(DemoService.class, + registryUrl, new ExchangeClient[] { new MockedClient("10.20.20.20", 2222, true) }); + registryProtocol.export(invoker); + } + + @Test + public void testExport() { + RegistryProtocol registryProtocol = new RegistryProtocol(); + registryProtocol.setCluster(new FailfastCluster()); + registryProtocol.setRegistryFactory(ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension()); + + Protocol dubboProtocol = new DubboProtocol(); + registryProtocol.setProtocol(dubboProtocol); + registryUrl = registryUrl.addParameter(RpcConstants.EXPORT_KEY, serviceUrl); + DubboInvoker invoker = new DubboInvoker(DemoService.class, + registryUrl, new ExchangeClient[] { new MockedClient("10.20.20.20", 2222, true) }); + Exporter exporter = registryProtocol.export(invoker); + assertEquals(invoker, exporter.getInvoker()); + exporter.unexport(); + } + +} \ No newline at end of file diff --git a/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/status/RegistryStatusCheckerTest.java b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/status/RegistryStatusCheckerTest.java new file mode 100644 index 0000000000..71eb9f74b5 --- /dev/null +++ b/dubbo-registry/src/test/java/com/alibaba/dubbo/registry/status/RegistryStatusCheckerTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.registry.status; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; +import com.alibaba.dubbo.registry.support.SimpleRegistryExporter; + +/** + * StatusTest + * + * @author tony.chenl + */ +public class RegistryStatusCheckerTest { + + static { + SimpleRegistryExporter.exportIfAbsent(9090); + SimpleRegistryExporter.exportIfAbsent(9091); + } + URL registryUrl = URL.valueOf("dubbo://cat:cat@127.0.0.1:9090/"); + URL registryUrl2 = URL.valueOf("dubbo://cat:cat@127.0.0.1:9091"); + + @Before + public void setUp() { + AbstractRegistryFactory.destroyAll(); + } + + @Test + public void testCheckUnknown() { + assertEquals(Status.Level.UNKNOWN, new RegistryStatusChecker().check().getLevel()); + } + + @Test + public void testCheckOK() { + ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension().getRegistry(registryUrl); + ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension().getRegistry(registryUrl2); + StringBuilder buf = new StringBuilder(); + buf.append(registryUrl.getAddress()); + buf.append("(connected)"); + buf.append(","); + buf.append(registryUrl2.getAddress()); + buf.append("(connected)"); + assertEquals(Status.Level.OK, new RegistryStatusChecker().check().getLevel()); + assertEquals(buf.toString(), new RegistryStatusChecker().check().getMessage()); + } +} \ No newline at end of file diff --git a/dubbo-registry/src/test/resources/log4j.xml b/dubbo-registry/src/test/resources/log4j.xml new file mode 100644 index 0000000000..c735ec0dd2 --- /dev/null +++ b/dubbo-registry/src/test/resources/log4j.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-remoting/pom.xml b/dubbo-remoting/pom.xml new file mode 100644 index 0000000000..462b649681 --- /dev/null +++ b/dubbo-remoting/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-remoting + jar + Dubbo Remoting Module + The remoting module of dubbo project + + + com.alibaba + dubbo-common + ${project.parent.version} + + + org.jboss.netty + netty + + + org.apache.mina + mina-core + provided + true + + + org.slf4j + slf4j-api + test + + + org.glassfish.grizzly + grizzly-core + provided + true + + + \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Channel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Channel.java new file mode 100644 index 0000000000..8a4e4bb000 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Channel.java @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.InetSocketAddress; + +/** + * Channel. (API/SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.remoting.Client + * @see com.alibaba.dubbo.remoting.Server#getChannels() + * @see com.alibaba.dubbo.remoting.Server#getChannel(InetSocketAddress) + * @author qian.lei + * @author william.liangf + */ +public interface Channel extends Endpoint { + + /** + * get remote address. + * + * @return remote address. + */ + InetSocketAddress getRemoteAddress(); + + /** + * is connected. + * + * @return connected + */ + boolean isConnected(); + + /** + * has attribute. + * + * @param key key. + * @return has or has not. + */ + boolean hasAttribute(String key); + + /** + * get attribute. + * + * @param key key. + * @return value. + */ + Object getAttribute(String key); + + /** + * set attribute. + * + * @param key key. + * @param value value. + */ + void setAttribute(String key,Object value); + + /** + * remove attribute. + * + * @param key key. + */ + void removeAttribute(String key); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ChannelHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ChannelHandler.java new file mode 100644 index 0000000000..18578a29e4 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ChannelHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + + +/** + * ChannelHandler. (API, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.remoting.exchange.Exchangers#bind(com.alibaba.dubbo.common.URL, ChannelHandler...) + * @see com.alibaba.dubbo.remoting.Transporter#bind(com.alibaba.dubbo.common.URL, ChannelHandler) + * @see com.alibaba.dubbo.remoting.exchange.Exchangers#connect(com.alibaba.dubbo.common.URL, ChannelHandler...) + * @see com.alibaba.dubbo.remoting.Transporter#connect(com.alibaba.dubbo.common.URL, ChannelHandler) + * @author qian.lei + * @author william.liangf + */ +public interface ChannelHandler { + + /** + * on channel connected. + * + * @param channel channel. + */ + void connected(Channel channel) throws RemotingException; + + /** + * on channel disconnected. + * + * @param channel channel. + */ + void disconnected(Channel channel) throws RemotingException; + + /** + * on message sent. + * + * @param channel channel. + * @param message message. + */ + void sent(Channel channel, Object message) throws RemotingException; + + /** + * on message received. + * + * @param channel channel. + * @param message message. + */ + void received(Channel channel, Object message) throws RemotingException; + + /** + * on exception caught. + * + * @param channel channel. + * @param exception exception. + */ + void caught(Channel channel, Throwable exception) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ChannelHandlerWrapper.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ChannelHandlerWrapper.java new file mode 100644 index 0000000000..1544b6d81e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ChannelHandlerWrapper.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.transport.support.handler.DefaultChannelHandlerWrapper; + +/** + * ChannelHandlerWrapper (SPI, Singleton, ThreadSafe) + * + * @author chao.liuc + */ +@Extension(DefaultChannelHandlerWrapper.NAME) +public interface ChannelHandlerWrapper { + + /** + * wrap. + * + * @param handler + * @param url + * @return + */ + @Adaptive({Constants.CHANNEL_HANDLER_KEY}) + ChannelHandler wrap(ChannelHandler handler, URL url); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Client.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Client.java new file mode 100644 index 0000000000..81131aa2aa --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Client.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +/** + * Remoting Client. (API/SPI, Prototype, ThreadSafe) + * + * Client/Server + * + * @see com.alibaba.dubbo.remoting.exchange.Exchangers#connect(com.alibaba.dubbo.common.URL, ChannelHandler...) + * @see com.alibaba.dubbo.remoting.Transporter#connect(com.alibaba.dubbo.common.URL, ChannelHandler) + * @author qian.lei + */ +public interface Client extends Endpoint, Channel, Resetable { + + /** + * reconnect. + */ + void reconnect() throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Codec.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Codec.java new file mode 100644 index 0000000000..3157650915 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Codec.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; + +/** + * Codec. (SPI, Singleton, ThreadSafe) + * + * @author qianlei + * @author ding.lid + * @author william.liangf + */ +@Extension +public interface Codec { + + /** + * Need more input poison. + * + * @see #decode(Channel, InputStream) + */ + Object NEED_MORE_INPUT = new Object(); + + /** + * Encode message. + * + * @param channel channel. + * @param output output stream. + * @param message message. + */ + @Adaptive({Constants.CODEC_KEY}) + void encode(Channel channel, OutputStream output, Object message) throws IOException; + + /** + * Decode message. + * + * @see #NEED_MORE_INPUT + * @param channel channel. + * @param input input stream. + * @return message or NEED_MORE_INPUT poison. + */ + @Adaptive({Constants.CODEC_KEY}) + Object decode(Channel channel, InputStream input) throws IOException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Endpoint.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Endpoint.java new file mode 100644 index 0000000000..267ad3031e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Endpoint.java @@ -0,0 +1,86 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.URL; + +/** + * Endpoint. (API/SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.remoting.Channel + * @see com.alibaba.dubbo.remoting.Client + * @see com.alibaba.dubbo.remoting.Server + * @author william.liangf + */ +public interface Endpoint { + + /** + * get url. + * + * @return url + */ + URL getUrl(); + + /** + * get channel handler. + * + * @return channel handler + */ + ChannelHandler getChannelHandler(); + + /** + * get local address. + * + * @return local address. + */ + InetSocketAddress getLocalAddress(); + + /** + * send message. + * + * @param message + * @throws RemotingException + */ + void send(Object message) throws RemotingException; + + /** + * send message. + * + * @param message + * @param sent 是否已发送完成 + */ + void send(Object message, boolean sent) throws RemotingException; + + /** + * close the channel. + */ + void close(); + + /** + * Graceful close the channel. + */ + void close(int timeout); + + /** + * is closed. + * + * @return closed + */ + boolean isClosed(); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ExecutionException.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ExecutionException.java new file mode 100644 index 0000000000..c54f6e4aa7 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/ExecutionException.java @@ -0,0 +1,67 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.InetSocketAddress; + +/** + * ReceiveException + * + * @author william.liangf + */ +public class ExecutionException extends RemotingException { + + private static final long serialVersionUID = -2531085236111056860L; + + private final Object request; + + public ExecutionException(Object request, Channel channel, String message, Throwable cause){ + super(channel, message, cause); + this.request = request; + } + + public ExecutionException(Object request, Channel channel, String msg){ + super(channel, msg); + this.request = request; + } + + public ExecutionException(Object request, Channel channel, Throwable cause){ + super(channel, cause); + this.request = request; + } + + public ExecutionException(Object request, InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message, + Throwable cause){ + super(localAddress, remoteAddress, message, cause); + this.request = request; + } + + public ExecutionException(Object request, InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message){ + super(localAddress, remoteAddress, message); + this.request = request; + } + + public ExecutionException(Object request, InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause){ + super(localAddress, remoteAddress, cause); + this.request = request; + } + + + public Object getRequest() { + return request; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/RemotingException.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/RemotingException.java new file mode 100644 index 0000000000..e7339e92e6 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/RemotingException.java @@ -0,0 +1,84 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.InetSocketAddress; + +/** + * RemotingException. (API, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.remoting.exchange.ResponseFuture#get() + * @see com.alibaba.dubbo.remoting.exchange.ResponseFuture#get(int) + * @see com.alibaba.dubbo.remoting.Channel#send(Object, boolean) + * @see com.alibaba.dubbo.remoting.Channel#request(Object) + * @see com.alibaba.dubbo.remoting.Channel#request(Object, int) + * @see com.alibaba.dubbo.remoting.Transporter#bind(com.alibaba.dubbo.common.URL, ChannelHandler) + * @see com.alibaba.dubbo.remoting.Transporter#connect(com.alibaba.dubbo.common.URL, ChannelHandler) + * @author qian.lei + */ +public class RemotingException extends Exception { + + private static final long serialVersionUID = -3160452149606778709L; + + private InetSocketAddress localAddress; + + private InetSocketAddress remoteAddress; + + public RemotingException(Channel channel, String msg){ + this(channel == null ? null : channel.getLocalAddress(), channel == null ? null : channel.getRemoteAddress(), + msg); + } + + public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message){ + super(message); + + this.localAddress = localAddress; + this.remoteAddress = remoteAddress; + } + + public RemotingException(Channel channel, Throwable cause){ + this(channel == null ? null : channel.getLocalAddress(), channel == null ? null : channel.getRemoteAddress(), + cause); + } + + public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause){ + super(cause); + + this.localAddress = localAddress; + this.remoteAddress = remoteAddress; + } + + public RemotingException(Channel channel, String message, Throwable cause){ + this(channel == null ? null : channel.getLocalAddress(), channel == null ? null : channel.getRemoteAddress(), + message, cause); + } + + public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message, + Throwable cause){ + super(message, cause); + + this.localAddress = localAddress; + this.remoteAddress = remoteAddress; + } + + public InetSocketAddress getLocalAddress() { + return localAddress; + } + + public InetSocketAddress getRemoteAddress() { + return remoteAddress; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Resetable.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Resetable.java new file mode 100644 index 0000000000..882bb2e147 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Resetable.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import com.alibaba.dubbo.common.URL; + +/** + * Resetable. + * + * @author william.liangf + */ +public interface Resetable { + + /** + * reset. + * + * @param url + */ + void reset(URL url); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Server.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Server.java new file mode 100755 index 0000000000..b75e81c4d9 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Server.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.InetSocketAddress; +import java.util.Collection; + +/** + * Remoting Server. (API/SPI, Prototype, ThreadSafe) + * + * Client/Server + * + * @see com.alibaba.dubbo.remoting.exchange.Exchangers#bind(com.alibaba.dubbo.common.URL, ChannelHandler...) + * @see com.alibaba.dubbo.remoting.Transporter#bind(com.alibaba.dubbo.common.URL, ChannelHandler) + * @author qian.lei + */ +public interface Server extends Endpoint, Resetable { + + /** + * is bound. + * + * @return bound + */ + boolean isBound(); + + /** + * get channels. + * + * @return channels + */ + Collection getChannels(); + + /** + * get channel. + * + * @param remoteAddress + * @return channel + */ + Channel getChannel(InetSocketAddress remoteAddress); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/TimeoutException.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/TimeoutException.java new file mode 100644 index 0000000000..1b20999536 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/TimeoutException.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.InetSocketAddress; + +/** + * TimeoutException. (API, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.remoting.exchange.ResponseFuture#get() + * @see com.alibaba.dubbo.remoting.exchange.ResponseFuture#get(int) + * @author qian.lei + */ +public class TimeoutException extends RemotingException { + + private static final long serialVersionUID = 3122966731958222692L; + + public static final int CLIENT_SIDE = 0; + + public static final int SERVER_SIDE = 1; + + private final int phase; + + public TimeoutException(boolean serverSide, Channel channel, String message){ + super(channel, message); + this.phase = serverSide ? SERVER_SIDE : CLIENT_SIDE; + } + + public TimeoutException(boolean serverSide, InetSocketAddress localAddress, + InetSocketAddress remoteAddress, String message) { + super(localAddress, remoteAddress, message); + this.phase = serverSide ? SERVER_SIDE : CLIENT_SIDE; + } + + public int getPhase() { + return phase; + } + + public boolean isServerSide() { + return phase == 1; + } + + public boolean isClientSide() { + return phase == 0; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Transporter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Transporter.java new file mode 100644 index 0000000000..425a44476d --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Transporter.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.transport.support.netty.NettyTransporter; + +/** + * Transporter. (SPI, Singleton, ThreadSafe) + * + * Transport Layer + * Client/Server + * + * @see com.alibaba.dubbo.remoting.exchange.Exchangers + * @author ding.lid + * @author william.liangf + */ +@Extension(NettyTransporter.NAME) +public interface Transporter { + + /** + * Bind a server. + * + * @see com.alibaba.dubbo.remoting.exchange.Exchangers#bind(URL, Receiver, ChannelHandler) + * @param url server url + * @param handler + * @return server + * @throws RemotingException + */ + @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY}) + Server bind(URL url, ChannelHandler handler) throws RemotingException; + + /** + * Connect to a server. + * + * @see com.alibaba.dubbo.remoting.Remoting#connect(URL, Receiver, ChannelListener) + * @param url server url + * @param handler + * @return client + * @throws RemotingException + */ + @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY}) + Client connect(URL url, ChannelHandler handler) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Transporters.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Transporters.java new file mode 100644 index 0000000000..aaec3a0359 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/Transporters.java @@ -0,0 +1,83 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerAdapter; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerDispatcher; + +/** + * Transporter facade. (API, Static, ThreadSafe) + * + * @author william.liangf + */ +public class Transporters { + + public static Server bind(String url, ChannelHandler... handler) throws RemotingException { + return bind(URL.valueOf(url), handler); + } + + public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + if (handlers == null || handlers.length == 0) { + throw new IllegalArgumentException("handlers == null"); + } + ChannelHandler handler; + if (handlers.length == 1) { + handler = handlers[0]; + } else { + handler = new ChannelHandlerDispatcher(handlers); + } + return getTransporter().bind(url, handler); + } + + public static Client connect(String url, ChannelHandler... handler) throws RemotingException { + return connect(URL.valueOf(url), handler); + } + + public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + ChannelHandler handler; + if (handlers == null || handlers.length == 0) { + handler = new ChannelHandlerAdapter(); + } else if (handlers.length == 1) { + handler = handlers[0]; + } else { + handler = new ChannelHandlerDispatcher(handlers); + } + return getTransporter().connect(url, handler); + } + + public static Transporter getTransporter() { + return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension(); + } + + static { + // check duplicate jar package + Version.checkDuplicate(Transporters.class); + Version.checkDuplicate(RemotingException.class); + } + + private Transporters(){ + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeChannel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeChannel.java new file mode 100644 index 0000000000..f59777b8aa --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeChannel.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * ExchangeChannel. (API/SPI, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public interface ExchangeChannel extends Channel { + + /** + * send request. + * + * @param request + * @return + * @throws RemotingException + */ + ResponseFuture request(Object request) throws RemotingException; + + /** + * send request. + * + * @param request + * @param timeout + * @return + * @throws RemotingException + */ + ResponseFuture request(Object request, int timeout) throws RemotingException; + + /** + * get message handler. + * + * @return message handler + */ + ExchangeHandler getExchangeHandler(); + + /** + * graceful close. + * + * @param timeout + */ + void close(int timeout); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeClient.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeClient.java new file mode 100644 index 0000000000..6e0d61c7d4 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeClient.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import com.alibaba.dubbo.remoting.Client; + +/** + * ExchangeClient. (API/SPI, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public interface ExchangeClient extends Client, ExchangeChannel { + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java new file mode 100644 index 0000000000..b5e183bf77 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; + +/** + * ExchangeHandler. (API, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public interface ExchangeHandler extends ChannelHandler, TelnetHandler { + + /** + * reply. + * + * @param channel + * @param request + * @return response + * @throws RemotingException + */ + Object reply(ExchangeChannel channel, Object request) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeServer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeServer.java new file mode 100644 index 0000000000..55ff1ba549 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeServer.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import java.net.InetSocketAddress; +import java.util.Collection; + +import com.alibaba.dubbo.remoting.Server; + +/** + * ExchangeServer. (API/SPI, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public interface ExchangeServer extends Server { + + /** + * get channels. + * + * @return channels + */ + Collection getExchangeChannels(); + + /** + * get channel. + * + * @param remoteAddress + * @return channel + */ + ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchanger.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchanger.java new file mode 100644 index 0000000000..10ab3ed10a --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchanger.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchanger; + +/** + * Exchanger. (SPI, Singleton, ThreadSafe) + * + * Message Exchange Pattern + * Request-Response + * + * @author william.liangf + */ +@Extension(HeaderExchanger.NAME) +public interface Exchanger { + + /** + * bind. + * + * @param url + * @param handler + * @return message server + */ + @Adaptive({Constants.EXCHANGER_KEY}) + ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException; + + /** + * connect. + * + * @param url + * @param handler + * @return message channel + */ + @Adaptive({Constants.EXCHANGER_KEY}) + ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchangers.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchangers.java new file mode 100644 index 0000000000..f55cd0edf8 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchangers.java @@ -0,0 +1,122 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerDispatcher; +import com.alibaba.dubbo.remoting.exchange.support.Replier; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerAdapter; + +/** + * Exchanger facade. (API, Static, ThreadSafe) + * + * @author william.liangf + */ +public class Exchangers { + + public static ExchangeServer bind(String url, Replier replier) throws RemotingException { + return bind(URL.valueOf(url), replier); + } + + public static ExchangeServer bind(URL url, Replier replier) throws RemotingException { + return bind(url, new ChannelHandlerAdapter(), replier); + } + + public static ExchangeServer bind(String url, ChannelHandler handler, Replier replier) throws RemotingException { + return bind(URL.valueOf(url), handler, replier); + } + + public static ExchangeServer bind(URL url, ChannelHandler handler, Replier replier) throws RemotingException { + return bind(url, new ExchangeHandlerDispatcher(replier, handler)); + } + + public static ExchangeServer bind(String url, ExchangeHandler handler) throws RemotingException { + return bind(URL.valueOf(url), handler); + } + + public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + if (handler == null) { + throw new IllegalArgumentException("handler == null"); + } + url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange"); + return getExchanger(url).bind(url, handler); + } + + public static ExchangeClient connect(String url) throws RemotingException { + return connect(URL.valueOf(url)); + } + + public static ExchangeClient connect(URL url) throws RemotingException { + return connect(url, new ChannelHandlerAdapter(), null); + } + + public static ExchangeClient connect(String url, Replier replier) throws RemotingException { + return connect(URL.valueOf(url), new ChannelHandlerAdapter(), replier); + } + + public static ExchangeClient connect(URL url, Replier replier) throws RemotingException { + return connect(url, new ChannelHandlerAdapter(), replier); + } + + public static ExchangeClient connect(String url, ChannelHandler handler, Replier replier) throws RemotingException { + return connect(URL.valueOf(url), handler, replier); + } + + public static ExchangeClient connect(URL url, ChannelHandler handler, Replier replier) throws RemotingException { + return connect(url, new ExchangeHandlerDispatcher(replier, handler)); + } + + public static ExchangeClient connect(String url, ExchangeHandler handler) throws RemotingException { + return connect(URL.valueOf(url), handler); + } + + public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + if (handler == null) { + throw new IllegalArgumentException("handler == null"); + } + url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange"); + return getExchanger(url).connect(url, handler); + } + + public static Exchanger getExchanger(URL url) { + String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER); + return getExchanger(type); + } + + public static Exchanger getExchanger(String type) { + return ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type); + } + + static { + // check duplicate jar package + Version.checkDuplicate(Exchangers.class); + } + + private Exchangers(){ + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Request.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Request.java new file mode 100644 index 0000000000..60e8328d5f --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Request.java @@ -0,0 +1,105 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * Request. + * + * @author qian.lei + * @author william.liangf + */ +public class Request { + + private static final AtomicLong INVOKE_ID = new AtomicLong(0); + + private final long mId; + + private String mVersion; + + private boolean mTwoWay = true; + + private boolean mHeatbeat = false; + + private boolean mBroken = false; + + private Object mData; + + public Request() { + mId = newId(); + } + + public Request(long id){ + mId = id; + } + + public long getId() { + return mId; + } + + public String getVersion() { + return mVersion; + } + + public void setVersion(String version) { + mVersion = version; + } + + public boolean isTwoWay() { + return mTwoWay; + } + + public void setTwoWay(boolean twoWay) { + mTwoWay = twoWay; + } + + public boolean isHeartbeat() { + return mHeatbeat; + } + + public void setHeartbeat(boolean isHeartbeat) { + this.mHeatbeat = isHeartbeat; + } + + public boolean isBroken() { + return mBroken; + } + + public void setBroken(boolean mBroken) { + this.mBroken = mBroken; + } + + public Object getData() { + return mData; + } + + public void setData(Object msg) { + mData = msg; + } + + private static long newId() { + // getAndIncrement()增长到MAX_VALUE时,再增长会变为MIN_VALUE,负数也可以做为ID + return INVOKE_ID.getAndIncrement(); + } + + @Override + public String toString() { + return "Request [id=" + mId + ", version=" + mVersion + ", twoway=" + mTwoWay + ", heatbeat=" + mHeatbeat + + ", broken=" + mBroken + ", data=" + (mData == this ? "this" : mData) + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java new file mode 100644 index 0000000000..7bb3653175 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java @@ -0,0 +1,143 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +/** + * Response + * + * @author qian.lei + * @author william.liangf + */ +public class Response { + + /** + * ok. + */ + public static final byte OK = 20; + + /** + * clien side timeout. + */ + public static final byte CLIENT_TIMEOUT = 30; + + /** + * server side timeout. + */ + public static final byte SERVER_TIMEOUT = 31; + + /** + * request format error. + */ + public static final byte BAD_REQUEST = 40; + + /** + * service not found. + */ + public static final byte SERVICE_NOT_FOUND = 60; + + /** + * service error. + */ + public static final byte SERVICE_ERROR = 70; + + /** + * internal server error. + */ + public static final byte SERVER_ERROR = 80; + + /** + * internal server error. + */ + public static final byte CLIENT_ERROR = 90; + + private long mId = 0; + + private String mVersion; + + private byte mStatus = OK; + + private boolean mHeatbeat = false; + + private String mErrorMsg; + + private Object mResult; + + public Response(){ + } + + public Response(long id){ + mId = id; + } + + public Response(long id, String version){ + mId = id; + mVersion = version; + } + + public long getId() { + return mId; + } + + public void setId(long id) { + mId = id; + } + + public String getVersion() { + return mVersion; + } + + public void setVersion(String version) { + mVersion = version; + } + + public byte getStatus() { + return mStatus; + } + + public void setStatus(byte status) { + mStatus = status; + } + + public boolean isHeartbeat() { + return mHeatbeat; + } + + public void setHeartbeat(boolean isHeatbeat) { + this.mHeatbeat = isHeatbeat; + } + + public Object getResult() { + return mResult; + } + + public void setResult(Object msg) { + mResult = msg; + } + + public String getErrorMessage() { + return mErrorMsg; + } + + public void setErrorMessage(String msg) { + mErrorMsg = msg; + } + + @Override + public String toString() { + return "Response [id=" + mId + ", version=" + mVersion + ", status=" + mStatus + ", heatbeat=" + mHeatbeat + + ", error=" + mErrorMsg + ", result=" + (mResult == this ? "this" : mResult) + "]"; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseCallback.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseCallback.java new file mode 100644 index 0000000000..efe3d8b516 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseCallback.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +/** + * Callback + * + * @author william.liangf + */ +public interface ResponseCallback { + + /** + * done. + * + * @param response + */ + void done(Object response); + + /** + * caught exception. + * + * @param exception + */ + void caught(Throwable exception); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseFuture.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseFuture.java new file mode 100644 index 0000000000..aabee8c603 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseFuture.java @@ -0,0 +1,59 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange; + +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * Future. (API/SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.remoting.Channel#request(Object) + * @see com.alibaba.dubbo.remoting.Channel#request(Object, int) + * @author qian.lei + * @author william.liangf + */ +public interface ResponseFuture { + + /** + * get result. + * + * @return result. + */ + Object get() throws RemotingException; + + /** + * get result with the specified timeout. + * + * @param timeoutInMillis timeout. + * @return result. + */ + Object get(int timeoutInMillis) throws RemotingException; + + /** + * set callback. + * + * @param callback + */ + void setCallback(ResponseCallback callback); + + /** + * check is done. + * + * @return done or not. + */ + boolean isDone(); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java new file mode 100644 index 0000000000..242b53fb67 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java @@ -0,0 +1,362 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.codec; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.io.StreamUtils; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.Response; +import com.alibaba.dubbo.remoting.telnet.codec.TelnetCodec; + +/** + * ExchangeCodec. + * + * @author qianlei + * @author william.liangf + */ +@Extension("exchange") +public class ExchangeCodec extends TelnetCodec { + + private static final Logger logger = LoggerFactory.getLogger(ExchangeCodec.class); + + // header length. + protected static final int HEADER_LENGTH = 16; + + // magic header. + protected static final short MAGIC = (short) 0xdabb; + + protected static final byte MAGIC_HIGH = (byte) Bytes.short2bytes(MAGIC)[0]; + + protected static final byte MAGIC_LOW = (byte) Bytes.short2bytes(MAGIC)[1]; + + // message flag. + protected static final byte FLAG_REQUEST = (byte) 0x80; + + protected static final byte FLAG_TWOWAY = (byte) 0x40; + + protected static final byte FLAG_HEARTBEAT = (byte) 0x20; + + protected static final int SERIALIZATION_MASK = 0x1f; + + private static Map ID_SERIALIZATION_MAP = new HashMap(); + static { + Set supportedExtensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions(); + for (String name : supportedExtensions) { + Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(name); + byte idByte = serialization.getContentTypeId(); + if (ID_SERIALIZATION_MAP.containsKey(idByte)) { + logger.error("Serialization extension " + serialization.getClass().getName() + + " has duplicate id to Serialization extension " + + ID_SERIALIZATION_MAP.get(idByte).getClass().getName() + + ", ignore this Serialization extension"); + continue; + } + ID_SERIALIZATION_MAP.put(idByte, serialization); + } + } + + public Short getMagicCode() { + return MAGIC; + } + + public void encode(Channel channel, OutputStream os, Object msg) throws IOException { + if (msg instanceof Request) { + encodeRequest(channel, os, (Request) msg); + } else if (msg instanceof Response) { + encodeResponse(channel, os, (Response) msg); + } else { + super.encode(channel, os, msg); + } + } + + public Object decode(Channel channel, InputStream is) throws IOException { + int readable = is.available(); + byte[] header = new byte[Math.min(readable, HEADER_LENGTH)]; + is.read(header); + return decode(channel, is, readable, header); + } + + protected Object decode(Channel channel, InputStream is, int readable, byte[] header) throws IOException { + // check magic number. + if (readable > 0 && header[0] != MAGIC_HIGH + || readable > 1 && header[1] != MAGIC_LOW) { + int length = header.length; + if (header.length < readable) { + header = Bytes.copyOf(header, readable); + is.read(header, length, readable - length); + } + for (int i = 1; i < header.length - 1; i ++) { + if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) { + UnsafeByteArrayInputStream bis = ((UnsafeByteArrayInputStream) is); + bis.position(bis.position() - header.length + i); + header = Bytes.copyOf(header, i); + break; + } + } + return super.decode(channel, is, readable, header); + } + // check length. + if (readable < HEADER_LENGTH) { + return NEED_MORE_INPUT; + } + + // get data length. + int len = Bytes.bytes2int(header, 12); + checkPayload(channel, len); + + int tt = len + HEADER_LENGTH; + if( readable < tt ) { + return NEED_MORE_INPUT; + } + + // limit input stream. + if( readable != tt ) + is = StreamUtils.limitedInputStream(is, len); + + byte flag = header[2], proto = (byte)( flag & SERIALIZATION_MASK ); + Serialization s = getSerializationById(proto); + if (s == null) { + s = getSerialization(channel); + } + ObjectInput in = s.deserialize(channel.getUrl(), is); + // get request id. + long id = Bytes.bytes2long(header, 4); + if( ( flag & FLAG_REQUEST ) == 0 ) { + // decode response. + Response res = new Response(id); + res.setHeartbeat( ( flag & FLAG_HEARTBEAT ) != 0 ); + // get status. + byte status = header[3]; + res.setStatus(status); + if( status == Response.OK ) { + try { + Object data; + if (res.isHeartbeat()) { + data = decodeHeartbeatData(channel, in); + } else { + data = decodeResponseData(channel, in); + } + res.setResult(data); + } catch (Throwable t) { + res.setStatus(Response.CLIENT_ERROR); + res.setErrorMessage(StringUtils.toString(t)); + } + } else { + res.setErrorMessage(in.readUTF()); + } + return res; + } else { + // decode request. + Request req = new Request(id); + req.setVersion("2.0.0"); + req.setTwoWay( ( flag & FLAG_TWOWAY ) != 0 ); + req.setHeartbeat( ( flag & FLAG_HEARTBEAT ) != 0 ); + try { + Object data; + if (req.isHeartbeat()) { + data = decodeHeartbeatData(channel, in); + } else { + data = decodeRequestData(channel, in); + } + req.setData(data); + } catch (Throwable t) { + // bad request + req.setBroken(true); + req.setData(t); + } + return req; + } + } + + protected void encodeRequest(Channel channel, OutputStream os, Request req) throws IOException { + Serialization serialization = getSerialization(channel); + // header. + byte[] header = new byte[HEADER_LENGTH]; + // set magic number. + Bytes.short2bytes(MAGIC, header); + + // set request and serialization flag. + header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId()); + + if (req.isTwoWay()) header[2] |= FLAG_TWOWAY; + if (req.isHeartbeat()) header[2] |= FLAG_HEARTBEAT; + + // set request id. + Bytes.long2bytes(req.getId(), header, 4); + + // encode request data. + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + ObjectOutput out = serialization.serialize(channel.getUrl(), bos); + if (req.isHeartbeat()) { + encodeHeartbeatData(channel, out, req.getData()); + } else { + encodeRequestData(channel, out, req.getData()); + } + out.flushBuffer(); + bos.flush(); + bos.close(); + byte[] data = bos.toByteArray(); + Bytes.int2bytes(data.length, header, 12); + + // write + os.write(header); // write header. + os.write(data); // write data. + } + + protected void encodeResponse(Channel channel, OutputStream os, Response res) throws IOException { + Serialization serialization = getSerialization(channel); + // header. + byte[] header = new byte[HEADER_LENGTH]; + // set magic number. + Bytes.short2bytes(MAGIC, header); + // set request and serialization flag. + header[2] = serialization.getContentTypeId(); + if (res.isHeartbeat()) header[2] |= FLAG_HEARTBEAT; + // set response status. + byte status = res.getStatus(); + header[3] = status; + // set request id. + Bytes.long2bytes(res.getId(), header, 4); + + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + ObjectOutput out = serialization.serialize(channel.getUrl(), bos); + // encode response data or error message. + if (status == Response.OK) { + if (res.isHeartbeat()) { + encodeHeartbeatData(channel, out, res.getResult()); + } else { + encodeResponseData(channel, out, res.getResult()); + } + } + else out.writeUTF(res.getErrorMessage()); + out.flushBuffer(); + bos.flush(); + bos.close(); + + byte[] data = bos.toByteArray(); + Bytes.int2bytes(data.length, header, 12); + // write + os.write(header); // write header. + os.write(data); // write data. + } + + private static final Serialization getSerializationById(Byte id) { + return ID_SERIALIZATION_MAP.get(id); + } + + @Override + protected Object decodeData(ObjectInput in) throws IOException { + return decodeRequestData(in); + } + + protected Object decodeHeartbeatData(ObjectInput in) throws IOException { + try { + return in.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read object failed.", e)); + } + } + + protected Object decodeRequestData(ObjectInput in) throws IOException { + try { + return in.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read object failed.", e)); + } + } + + protected Object decodeResponseData(ObjectInput in) throws IOException { + try { + return in.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read object failed.", e)); + } + } + + @Override + protected void encodeData(ObjectOutput out, Object data) throws IOException { + encodeRequestData(out, data); + } + + protected void encodeHeartbeatData(ObjectOutput out, Object data) throws IOException { + out.writeObject(data); + } + + protected void encodeRequestData(ObjectOutput out, Object data) throws IOException { + out.writeObject(data); + } + + protected void encodeResponseData(ObjectOutput out, Object data) throws IOException { + out.writeObject(data); + } + + @Override + protected Object decodeData(Channel channel, ObjectInput in) throws IOException { + return decodeRequestData(channel ,in); + } + + protected Object decodeHeartbeatData(Channel channel, ObjectInput in) throws IOException { + try { + return in.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read object failed.", e)); + } + } + + protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException { + return decodeRequestData(in); + } + + protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException { + return decodeRequestData(in); + } + + @Override + protected void encodeData(Channel channel, ObjectOutput out, Object data) throws IOException { + encodeRequestData(channel, out, data); + } + + protected void encodeHeartbeatData(Channel channel, ObjectOutput out, Object data) throws IOException { + encodeHeartbeatData(out, data); + } + + protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { + encodeRequestData(out, data); + } + + protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException { + encodeResponseData(out, data); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java new file mode 100644 index 0000000000..7c1086fc6e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java @@ -0,0 +1,271 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.TimeoutException; +import com.alibaba.dubbo.remoting.exchange.ResponseCallback; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.Response; + +/** + * DefaultFuture. + * + * @author qian.lei + */ +public class DefaultFuture implements ResponseFuture { + + private static final Logger logger = LoggerFactory.getLogger(DefaultFuture.class); + + private static final Map CHANNELS = new ConcurrentHashMap(); + + private static final Map FUTURES = new ConcurrentHashMap(); + + // invoke id. + private final long id; + + private final Channel channel; + + private final Request request; + + private final int timeout; + + private final Lock lock = new ReentrantLock(); + + private final Condition done = lock.newCondition(); + + private final long start = System.currentTimeMillis(); + + private volatile long sent; + + private volatile Response response; + + private volatile ResponseCallback callback; + + public DefaultFuture(Channel channel, Request request, int timeout){ + this.channel = channel; + this.request = request; + this.id = request.getId(); + this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + // put into waiting map. + FUTURES.put(id, this); + CHANNELS.put(id, channel); + } + + public Object get() throws RemotingException { + return get(timeout); + } + + public Object get(int timeout) throws RemotingException { + if (timeout <= 0) { + timeout = Constants.DEFAULT_TIMEOUT; + } + if (! isDone()) { + long start = System.currentTimeMillis(); + lock.lock(); + try { + while (! isDone()) { + done.await(timeout, TimeUnit.MILLISECONDS); + if (isDone() || System.currentTimeMillis() - start > timeout) { + break; + } + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + lock.unlock(); + } + if (! isDone()) { + throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false)); + } + } + return returnFromResponse(); + } + + public void cancel(){ + response = new Response(id); + response.setErrorMessage("request future has been canceled."); + FUTURES.remove(id); + CHANNELS.remove(id); + } + + public boolean isDone() { + return response != null; + } + + public void setCallback(ResponseCallback callback) { + if (isDone()) { + try { + callback.done(returnFromResponse()); + } catch (Throwable e) { + callback.caught(e); + } + } else { + this.callback = callback; + } + } + + private long getId() { + return id; + } + + private Channel getChannel() { + return channel; + } + + private boolean isSent() { + return sent > 0; + } + + public Request getRequest() { + return request; + } + + private int getTimeout() { + return timeout; + } + + private long getStartTimestamp() { + return start; + } + + public static boolean hasFuture(Channel channel) { + return CHANNELS.containsValue(channel); + } + + public static void sent(Channel channel, Request request) { + DefaultFuture future = FUTURES.get(request.getId()); + if (future != null) { + future.doSent(); + } + } + + private void doSent() { + sent = System.currentTimeMillis(); + } + + public static void received(Channel channel, Response response) { + try { + DefaultFuture future = FUTURES.remove(response.getId()); + if (future != null) { + future.doReceived(response); + } else { + logger.warn("The timeout reponse finally returned at " + + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())) + + ", response " + response + + (channel == null ? "" : ", channel: " + channel.getLocalAddress() + + " -> " + channel.getRemoteAddress())); + } + } finally { + CHANNELS.remove(response.getId()); + } + } + + private void doReceived(Response res) { + lock.lock(); + try { + response = res; + if (done != null) { + done.signal(); + } + } finally { + lock.unlock(); + } + ResponseCallback c = callback; + if (c != null) { + try { + c.done(returnFromResponse()); + } catch (Throwable e) { + c.caught(e); + } + callback = null; + } + } + + private Object returnFromResponse() throws RemotingException { + Response res = response; + if (res.getStatus() == Response.OK) { + return response.getResult(); + } + if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) { + throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()); + } + FUTURES.remove(id); + CHANNELS.remove(id); + throw new RemotingException(channel, res.getErrorMessage()); + } + + private String getTimeoutMessage(boolean scan) { + long nowTimestamp = System.currentTimeMillis(); + return (sent > 0 ? "Waiting server-side response timeout" : "Sending request timeout in client-side") + + (scan ? " by scan timer" : "") + ". start time: " + + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(start))) + ", end time: " + + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())) + "," + + (sent > 0 ? " client elapsed: " + (sent - start) + + " ms, server elapsed: " + (nowTimestamp - sent) + : " elapsed: " + (nowTimestamp - start)) + " ms, timeout: " + + timeout + " ms, request: " + request + ", channel: " + channel.getLocalAddress() + + " -> " + channel.getRemoteAddress(); + } + + private static class RemotingInvocationTimeoutScan implements Runnable { + + public void run() { + while (true) { + try { + for (DefaultFuture future : FUTURES.values()) { + if (future == null || future.isDone()) { + continue; + } + if (System.currentTimeMillis() - future.getStartTimestamp() > future.getTimeout()) { + // create exception response. + Response timeoutResponse = new Response(future.getId()); + // set timeout status. + timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT); + timeoutResponse.setErrorMessage(future.getTimeoutMessage(true)); + // handle response. + DefaultFuture.received(future.getChannel(), timeoutResponse); + } + } + Thread.sleep(30); + } catch (Throwable e) { + logger.error("Exception when scan the timeout invocation of remoting.", e); + } + } + } + } + + static { + Thread th = new Thread(new RemotingInvocationTimeoutScan(), "remoting-invocation-timeout-scan"); + th.setDaemon(true); + th.start(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java new file mode 100644 index 0000000000..378d7fbb6f --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.telnet.support.TelnetHandlerAdapter; + +/** + * ExchangeHandlerAdapter + * + * @author william.liangf + */ +public abstract class ExchangeHandlerAdapter extends TelnetHandlerAdapter implements ExchangeHandler { + + public Object reply(ExchangeChannel channel, Object msg) throws RemotingException { + return null; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java new file mode 100644 index 0000000000..9bded2c099 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java @@ -0,0 +1,113 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support; + +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.TelnetHandlerAdapter; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerDispatcher; + +/** + * ExchangeHandlerDispatcher + * + * @author william.liangf + */ +public class ExchangeHandlerDispatcher implements ExchangeHandler { + + private final ReplierDispatcher replierDispatcher; + + private final ChannelHandlerDispatcher handlerDispatcher; + + private final TelnetHandler telnetHandler; + + public ExchangeHandlerDispatcher() { + replierDispatcher = new ReplierDispatcher(); + handlerDispatcher = new ChannelHandlerDispatcher(); + telnetHandler = new TelnetHandlerAdapter(); + } + + public ExchangeHandlerDispatcher(Replier replier){ + replierDispatcher = new ReplierDispatcher(replier); + handlerDispatcher = new ChannelHandlerDispatcher(); + telnetHandler = new TelnetHandlerAdapter(); + } + + public ExchangeHandlerDispatcher(ChannelHandler... handlers){ + replierDispatcher = new ReplierDispatcher(); + handlerDispatcher = new ChannelHandlerDispatcher(handlers); + telnetHandler = new TelnetHandlerAdapter(); + } + + public ExchangeHandlerDispatcher(Replier replier, ChannelHandler... handlers){ + replierDispatcher = new ReplierDispatcher(replier); + handlerDispatcher = new ChannelHandlerDispatcher(handlers); + telnetHandler = new TelnetHandlerAdapter(); + } + + public ExchangeHandlerDispatcher addChannelHandler(ChannelHandler handler) { + handlerDispatcher.addChannelHandler(handler); + return this; + } + + public ExchangeHandlerDispatcher removeChannelHandler(ChannelHandler handler) { + handlerDispatcher.removeChannelHandler(handler); + return this; + } + + public ExchangeHandlerDispatcher addReplier(Class type, Replier replier) { + replierDispatcher.addReplier(type, replier); + return this; + } + + public ExchangeHandlerDispatcher removeReplier(Class type) { + replierDispatcher.removeReplier(type); + return this; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + return ((Replier)replierDispatcher).reply(channel, request); + } + + public void connected(Channel channel) { + handlerDispatcher.connected(channel); + } + + public void disconnected(Channel channel) { + handlerDispatcher.disconnected(channel); + } + + public void sent(Channel channel, Object message) { + handlerDispatcher.sent(channel, message); + } + + public void received(Channel channel, Object message) { + handlerDispatcher.received(channel, message); + } + + public void caught(Channel channel, Throwable exception) { + handlerDispatcher.caught(channel, exception); + } + + public String telnet(Channel channel, String message) throws RemotingException { + return telnetHandler.telnet(channel, message); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeServerDelegate.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeServerDelegate.java new file mode 100644 index 0000000000..dc0f9fcaff --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeServerDelegate.java @@ -0,0 +1,108 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support; + +import java.net.InetSocketAddress; +import java.util.Collection; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; + +/** + * ExchangeServerDelegate + * + * @author william.liangf + */ +public class ExchangeServerDelegate implements ExchangeServer { + + private transient ExchangeServer server; + + public ExchangeServerDelegate() { + } + + public ExchangeServerDelegate(ExchangeServer server){ + setServer(server); + } + + public ExchangeServer getServer() { + return server; + } + + public void setServer(ExchangeServer server) { + this.server = server; + } + + public boolean isBound() { + return server.isBound(); + } + + public void reset(URL url) { + server.reset(url); + } + + public Collection getChannels() { + return server.getChannels(); + } + + public Channel getChannel(InetSocketAddress remoteAddress) { + return server.getChannel(remoteAddress); + } + + public URL getUrl() { + return server.getUrl(); + } + + public ChannelHandler getChannelHandler() { + return server.getChannelHandler(); + } + + public InetSocketAddress getLocalAddress() { + return server.getLocalAddress(); + } + + public void send(Object message) throws RemotingException { + server.send(message); + } + + public void send(Object message, boolean sent) throws RemotingException { + server.send(message, sent); + } + + public void close() { + server.close(); + } + + public boolean isClosed() { + return server.isClosed(); + } + + public Collection getExchangeChannels() { + return server.getExchangeChannels(); + } + + public ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress) { + return server.getExchangeChannel(remoteAddress); + } + + public void close(int timeout) { + server.close(timeout); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/Replier.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/Replier.java new file mode 100755 index 0000000000..01a3c95cd0 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/Replier.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; + +/** + * Replier. (API, Prototype, ThreadSafe) + * + * @author william.liangf + */ +public interface Replier { + + /** + * reply. + * + * @param channel + * @param request + * @return response + * @throws RemotingException + */ + Object reply(ExchangeChannel channel, T request) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ReplierDispatcher.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ReplierDispatcher.java new file mode 100644 index 0000000000..8a7ff7c521 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ReplierDispatcher.java @@ -0,0 +1,77 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; + +/** + * ReplierDispatcher + * + * @author william.liangf + */ +public class ReplierDispatcher implements Replier { + + private final Replier defaultReplier; + + private final Map, Replier> repliers = new ConcurrentHashMap, Replier>(); + + public ReplierDispatcher(){ + this(null, null); + } + + public ReplierDispatcher(Replier defaultReplier){ + this(defaultReplier, null); + } + + public ReplierDispatcher(Replier defaultReplier, Map, Replier> repliers){ + this.defaultReplier = defaultReplier; + if (repliers != null && repliers.size() > 0) { + this.repliers.putAll(repliers); + } + } + + public ReplierDispatcher addReplier(Class type, Replier replier) { + repliers.put(type, replier); + return this; + } + + public ReplierDispatcher removeReplier(Class type) { + repliers.remove(type); + return this; + } + + private Replier getReplier(Class type) { + for(Map.Entry, Replier> entry : repliers.entrySet()) { + if(entry.getKey().isAssignableFrom(type)) { + return entry.getValue(); + } + } + if (defaultReplier != null) { + return defaultReplier; + } + throw new IllegalStateException("Replier not found, Unsupported message object: " + type); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + return ((Replier)getReplier(request.getClass())).reply(channel, request); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java new file mode 100644 index 0000000000..859272e6e7 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java @@ -0,0 +1,217 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support.header; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.Response; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.remoting.exchange.support.DefaultFuture; + +/** + * ExchangeReceiver + * + * @author william.liangf + */ +final class HeaderExchangeChannel implements ExchangeChannel { + + private static final Logger logger = LoggerFactory.getLogger(HeaderExchangeChannel.class); + + private static final String CHANNEL_KEY = HeaderExchangeChannel.class.getName() + ".CHANNEL"; + + private final Channel channel; + + private volatile boolean closed = false; + + HeaderExchangeChannel(Channel channel){ + if (channel == null) { + throw new IllegalArgumentException("channel == null"); + } + this.channel = channel; + } + + static HeaderExchangeChannel getOrAddChannel(Channel ch) { + if (ch == null) { + return null; + } + HeaderExchangeChannel ret = (HeaderExchangeChannel) ch.getAttribute(CHANNEL_KEY); + if (ret == null) { + ret = new HeaderExchangeChannel(ch); + if (ch.isConnected()) { + ch.setAttribute(CHANNEL_KEY, ret); + } + } + return ret; + } + + static void removeChannelIfDisconnected(Channel ch) { + if (ch != null && ! ch.isConnected()) { + ch.removeAttribute(CHANNEL_KEY); + } + } + + public void send(Object message) throws RemotingException { + send(message, getUrl().getBooleanParameter(Constants.SENT_KEY)); + } + + public void send(Object message, boolean sent) throws RemotingException { + if (closed) { + throw new RemotingException(this.getLocalAddress(), null, "Failed to send message " + message + ", cause: The channel " + this + " is closed!"); + } + if (message instanceof Request + || message instanceof Response + || message instanceof String) { + channel.send(message, sent); + } else { + Request request = new Request(); + request.setVersion("2.0.0"); + request.setTwoWay(false); + request.setData(message); + channel.send(request, sent); + } + } + + public ResponseFuture request(Object request) throws RemotingException { + return request(request, channel.getUrl().getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); + } + + public ResponseFuture request(Object request, int timeout) throws RemotingException { + if (closed) { + throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!"); + } + // create request. + Request req = new Request(); + req.setVersion("2.0.0"); + req.setTwoWay(true); + req.setData(request); + DefaultFuture future = new DefaultFuture(channel, req, timeout); + try{ + channel.send(req); + }catch (RemotingException e) { + future.cancel(); + throw e; + } + return future; + } + + public boolean isClosed() { + return closed; + } + + public void close() { + try { + channel.close(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + // graceful close + public void close(int timeout) { + if (closed) { + return; + } + closed = true; + if (timeout > 0) { + long start = System.currentTimeMillis(); + while (DefaultFuture.hasFuture(HeaderExchangeChannel.this) + && System.currentTimeMillis() - start < timeout) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + logger.warn(e.getMessage(), e); + } + } + } + close(); + } + + public InetSocketAddress getLocalAddress() { + return channel.getLocalAddress(); + } + + public InetSocketAddress getRemoteAddress() { + return channel.getRemoteAddress(); + } + + public URL getUrl() { + return channel.getUrl(); + } + + public boolean isConnected() { + return channel.isConnected(); + } + + public ChannelHandler getChannelHandler() { + return channel.getChannelHandler(); + } + + public ExchangeHandler getExchangeHandler() { + return (ExchangeHandler) channel.getChannelHandler(); + } + + public Object getAttribute(String key) { + return channel.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + channel.setAttribute(key, value); + } + + public void removeAttribute(String key) { + channel.removeAttribute(key); + } + + public boolean hasAttribute(String key) { + return channel.hasAttribute(key); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((channel == null) ? 0 : channel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + HeaderExchangeChannel other = (HeaderExchangeChannel) obj; + if (channel == null) { + if (other.channel != null) return false; + } else if (!channel.equals(other.channel)) return false; + return true; + } + + @Override + public String toString() { + return channel.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java new file mode 100644 index 0000000000..43e0771ca5 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support.header; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; + +/** + * DefaultMessageClient + * + * @author william.liangf + */ +public class HeaderExchangeClient implements ExchangeClient { + + private final Client client; + + private final ExchangeChannel channel; + + public HeaderExchangeClient(Client client){ + if (client == null) { + throw new IllegalArgumentException("client == null"); + } + this.client = client; + this.channel = new HeaderExchangeChannel(client); + } + + public ResponseFuture request(Object request) throws RemotingException { + return channel.request(request); + } + + public URL getUrl() { + return channel.getUrl(); + } + + public InetSocketAddress getRemoteAddress() { + return channel.getRemoteAddress(); + } + + public ResponseFuture request(Object request, int timeout) throws RemotingException { + return channel.request(request, timeout); + } + + public ChannelHandler getChannelHandler() { + return channel.getChannelHandler(); + } + + public boolean isConnected() { + return channel.isConnected(); + } + + public InetSocketAddress getLocalAddress() { + return channel.getLocalAddress(); + } + + public ExchangeHandler getExchangeHandler() { + return channel.getExchangeHandler(); + } + + public void send(Object message) throws RemotingException { + channel.send(message); + } + + public void send(Object message, boolean sent) throws RemotingException { + channel.send(message, sent); + } + + public boolean isClosed() { + return channel.isClosed(); + } + + public void close() { + channel.close(); + } + + public void close(int timeout) { + channel.close(timeout); + } + + public void reset(URL url) { + client.reset(url); + } + + public void reconnect() throws RemotingException { + client.reconnect(); + } + + public Object getAttribute(String key) { + return channel.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + channel.setAttribute(key, value); + } + + public void removeAttribute(String key) { + channel.removeAttribute(key); + } + + public boolean hasAttribute(String key) { + return channel.hasAttribute(key); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java new file mode 100644 index 0000000000..9ecc6972a6 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java @@ -0,0 +1,203 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support.header; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ExecutionException; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.Response; +import com.alibaba.dubbo.remoting.exchange.support.DefaultFuture; + +/** + * ExchangeReceiver + * + * @author william.liangf + */ +public class HeaderExchangeHandler implements ChannelHandler { + + protected static final Logger logger = LoggerFactory.getLogger(HeaderExchangeHandler.class); + + public static String KEY_READ_TIMESTAMP = "READ_TIMESTAMP"; + + public static String KEY_WRITE_TIMESTAMP = "WRITE_TIMESTAMP"; + + private final ExchangeHandler handler; + + public HeaderExchangeHandler(ExchangeHandler handler){ + if (handler == null) { + throw new IllegalArgumentException("handler == null"); + } + this.handler = handler; + } + + Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException { + Response res = new Response(req.getId(), req.getVersion()); + if (req.isHeartbeat()) { + res.setHeartbeat(true); + return res; + } + + if (req.isBroken()) { + Object data = req.getData(); + + String msg; + if (data == null) msg = null; + else if (data instanceof Throwable) msg = StringUtils.toString((Throwable) data); + else msg = data.toString(); + res.setErrorMessage("Fail to decode request due to: " + msg); + res.setStatus(Response.BAD_REQUEST); + + return res; + } + + // find handler by message class. + Object msg = req.getData(); + if (handler == null) {// no handler. + res.setStatus(Response.SERVICE_NOT_FOUND); + res.setErrorMessage("InvokeHandler not found, Unsupported protocol object: " + msg); + } else { + try { + // handle data. + Object result = handler.reply(channel, msg); + res.setStatus(Response.OK); + res.setResult(result); + } catch (Throwable e) { + res.setStatus(Response.SERVICE_ERROR); + res.setErrorMessage(StringUtils.toString(e)); + } + } + return res; + } + + static void handleResponse(Channel channel, Response response) throws RemotingException { + if (response != null && !response.isHeartbeat()) { + DefaultFuture.received(channel, response); + } + } + + public void connected(Channel channel) throws RemotingException { + channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis()); + channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); + ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); + try { + handler.connected(exchangeChannel); + } finally { + HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + } + + public void disconnected(Channel channel) throws RemotingException { + channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis()); + channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); + ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); + try { + handler.disconnected(exchangeChannel); + } finally { + HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + } + + public void sent(Channel channel, Object message) throws RemotingException { + Throwable exception = null; + try { + channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); + ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); + try { + handler.sent(exchangeChannel, message); + } finally { + HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + } catch (Throwable t) { + exception = t; + } + if (message instanceof Request) { + Request request = (Request) message; + DefaultFuture.sent(channel, request); + } + if (exception != null) { + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } else if (exception instanceof RemotingException) { + throw (RemotingException) exception; + } else { + throw new RemotingException(channel.getLocalAddress(), channel.getRemoteAddress(), + exception.getMessage(), exception); + } + } + } + + public void received(Channel channel, Object message) throws RemotingException { + channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis()); + ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); + try { + if (message instanceof Request) { + // handle request. + Request request = (Request) message; + if (request.isTwoWay()) { + Response response = handleRequest(exchangeChannel, request); + if (response == null) { + throw new RemotingException(channel, "Response is null."); + } + channel.send(response); + } else { + handler.received(exchangeChannel, request.getData()); + } + } else if (message instanceof Response) { + handleResponse(channel, (Response) message); + } else if (message instanceof String) { + String echo = handler.telnet(channel, (String) message); + if (echo != null && echo.length() > 0) { + channel.send(echo); + } + } else { + handler.received(exchangeChannel, message); + } + } finally { + HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + if (exception instanceof ExecutionException) { + ExecutionException e = (ExecutionException) exception; + Object msg = e.getRequest(); + if (msg instanceof Request) { + Request req = (Request) msg; + if (req.isTwoWay() && ! req.isHeartbeat()) { + Response res = new Response(req.getId(), req.getVersion()); + res.setStatus(Response.SERVER_ERROR); + res.setErrorMessage(StringUtils.toString(e)); + channel.send(res); + return; + } + } + } + ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); + try { + handler.caught(exchangeChannel, exception); + } finally { + HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java new file mode 100644 index 0000000000..6de2ad852f --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java @@ -0,0 +1,264 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support.header; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.support.DefaultFuture; + +/** + * ExchangeServerImpl + * + * @author william.liangf + */ +public class HeaderExchangeServer implements ExchangeServer { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1, + new NamedThreadFactory( + "dubbo-remoting-server-heartbeat", + true)); + + // 心跳定时器 + private ScheduledFuture heatbeatTimer; + + // 心跳超时,毫秒。缺省0,不会执行心跳。 + private int heartbeat; + + private int heartbeatTimeout; + + private final Server server; + + private volatile boolean closed = false; + + public HeaderExchangeServer(Server server) { + if (server == null) { + throw new IllegalArgumentException("server == null"); + } + this.server = server; + this.heartbeat = server.getUrl().getIntParameter(Constants.HEARTBEAT_KEY, Constants.DEFAULT_HEARTBEAT); + this.heartbeatTimeout = server.getUrl().getIntParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3); + if (heartbeatTimeout < heartbeat * 2) { + throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2"); + } + startHeatbeatTimer(); + } + + public Server getServer() { + return server; + } + + public boolean isClosed() { + return server.isClosed(); + } + + private boolean isRunning() { + Collection channels = getChannels(); + for (Channel channel : channels) { + if (DefaultFuture.hasFuture(channel)) { + return true; + } + } + return false; + } + + public void close() { + doClose(); + server.close(); + } + + public void close(final int timeout) { + if (timeout > 0) { + final long max = (long) timeout; + final long start = System.currentTimeMillis(); + while (HeaderExchangeServer.this.isRunning() + && System.currentTimeMillis() - start < max) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + logger.warn(e.getMessage(), e); + } + } + } + doClose(); + server.close(timeout); + } + + private void doClose() { + if (closed) { + return; + } + closed = true; + try { + if (null != heatbeatTimer) { + heatbeatTimer.cancel(true); + heatbeatTimer = null; + } + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + try { + scheduled.shutdown(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + + public Collection getExchangeChannels() { + Collection exchangeChannels = new ArrayList(); + Collection channels = server.getChannels(); + if (channels != null && channels.size() > 0) { + for (Channel channel : channels) { + exchangeChannels.add(HeaderExchangeChannel.getOrAddChannel(channel)); + } + } + return exchangeChannels; + } + + public ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress) { + Channel channel = server.getChannel(remoteAddress); + return HeaderExchangeChannel.getOrAddChannel(channel); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Collection getChannels() { + return (Collection)getExchangeChannels(); + } + + public Channel getChannel(InetSocketAddress remoteAddress) { + return getExchangeChannel(remoteAddress); + } + + public boolean isBound() { + return server.isBound(); + } + + public InetSocketAddress getLocalAddress() { + return server.getLocalAddress(); + } + + public URL getUrl() { + return server.getUrl(); + } + + public ChannelHandler getChannelHandler() { + return server.getChannelHandler(); + } + + public void reset(URL url) { + server.reset(url); + try { + if (url.hasParameter(Constants.HEARTBEAT_KEY) + || url.hasParameter(Constants.HEARTBEAT_TIMEOUT_KEY)) { + int h = url.getIntParameter(Constants.HEARTBEAT_KEY, heartbeat); + int t = url.getIntParameter(Constants.HEARTBEAT_TIMEOUT_KEY, h * 3); + if (t < h * 2) { + throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2"); + } + if (h != heartbeat || t != heartbeatTimeout) { + heartbeat = h; + heartbeatTimeout = t; + startHeatbeatTimer(); + } + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + + public void send(Object message) throws RemotingException { + if (closed) { + throw new RemotingException(this.getLocalAddress(), null, "Failed to send message " + message + ", cause: The server " + getLocalAddress() + " is closed!"); + } + server.send(message); + } + + public void send(Object message, boolean sent) throws RemotingException { + if (closed) { + throw new RemotingException(this.getLocalAddress(), null, "Failed to send message " + message + ", cause: The server " + getLocalAddress() + " is closed!"); + } + server.send(message, sent); + } + + private void startHeatbeatTimer() { + try { + ScheduledFuture timer = heatbeatTimer; + if (timer != null && ! timer.isCancelled()) { + timer.cancel(true); + } + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + if (heartbeat > 0) { + heatbeatTimer = scheduled.scheduleWithFixedDelay(new HeartBeatTask(), heartbeat, heartbeat, + TimeUnit.MILLISECONDS); + } + } + + private class HeartBeatTask implements Runnable { + public void run() { + try { + long now = System.currentTimeMillis(); + for (Channel channel : getChannels()) { + try { + Long lastRead = (Long) channel.getAttribute(HeaderExchangeHandler.KEY_READ_TIMESTAMP); + Long lastWrite = (Long) channel.getAttribute(HeaderExchangeHandler.KEY_WRITE_TIMESTAMP); + if ((lastRead != null && now - lastRead > heartbeat) + || (lastWrite != null && now - lastWrite > heartbeat)) { + Request req = new Request(); + req.setVersion("2.0.0"); + req.setTwoWay(true); + req.setHeartbeat(true); + channel.send(req); + if (logger.isDebugEnabled()) { + logger.debug("Send heartbeat to client " + channel.getRemoteAddress() + "."); + } + } + if (lastRead != null && now - lastRead > heartbeatTimeout) { + logger.warn("Close remote client " + channel.getRemoteAddress() + + ", because heartbeat read idle time out."); + channel.close(); + } + } catch (Throwable t) { + logger.warn("Exception when heartbeat to client " + (InetSocketAddress) channel.getRemoteAddress(), t); + } + } + } catch (Throwable t) { + logger.info("Exception when heartbeat to clients: ", t); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchanger.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchanger.java new file mode 100644 index 0000000000..c1506ade9e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchanger.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.exchange.support.header; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Transporters; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchanger; + +/** + * DefaultMessenger + * + * @author william.liangf + */ +@Extension(HeaderExchanger.NAME) +public class HeaderExchanger implements Exchanger { + + public static final String NAME = "header"; + + public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { + return new HeaderExchangeClient(Transporters.connect(url, new HeaderExchangeHandler(handler))); + } + + public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { + return new HeaderExchangeServer(Transporters.bind(url, new HeaderExchangeHandler(handler))); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Group.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Group.java new file mode 100644 index 0000000000..60d003168e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Group.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * Group. (SPI, Prototype, ThreadSafe) + * + * Peer-to-peer + * + * @author william.liangf + */ +public interface Group { + + /** + * get group url. + * + * @return group url. + */ + URL getUrl(); + + /** + * join. + * + * @param url + */ + Peer join(URL url, ChannelHandler handler) throws RemotingException; + + /** + * leave. + * + * @param url + * @throws RemotingException + */ + void leave(URL url) throws RemotingException; + + /** + * close the group. + */ + void close(); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Networker.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Networker.java new file mode 100644 index 0000000000..c7fafe16c7 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Networker.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * Networker. (SPI, Singleton, ThreadSafe) + * + * Peer-to-peer + * + * @author william.liangf + */ +@Extension +public interface Networker { + + /** + * lookup group. + * + * @param url group url + * @return group. + */ + Group lookup(URL url) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Networkers.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Networkers.java new file mode 100644 index 0000000000..46c1ce6897 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Networkers.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * Networkers. (API, Static, ThreadSafe) + * + * Peer-to-peer + * + * @author william.liangf + */ +public class Networkers { + + public static Peer join(String group, String peer, ChannelHandler handler) throws RemotingException { + return join(URL.valueOf(group), URL.valueOf(peer), handler); + } + + public static Peer join(URL group, URL peer, ChannelHandler handler) throws RemotingException { + return lookup(group).join(peer, handler); + } + + public static Group lookup(String group) throws RemotingException { + return lookup(URL.valueOf(group)); + } + + public static Group lookup(URL group) throws RemotingException { + Networker networker = ExtensionLoader.getExtensionLoader(Networker.class).getExtension(group.getProtocol()); + return networker.lookup(group); + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Peer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Peer.java new file mode 100644 index 0000000000..5f511746a1 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/Peer.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; + +/** + * Peer. (SPI, Prototype, ThreadSafe) + * + * Peer-to-peer + * + * @author william.liangf + */ +public interface Peer extends Server { + + /** + * leave. + * + * @throws RemotingException + */ + void leave() throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeGroup.java new file mode 100644 index 0000000000..a72587c5b7 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeGroup.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.p2p.Group; + +/** + * Group + * + * @author william.liangf + */ +public interface ExchangeGroup extends Group { + + /** + * join. + * + * @param url + */ + ExchangePeer join(URL url, ExchangeHandler handler) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeNetworker.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeNetworker.java new file mode 100644 index 0000000000..8437119585 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeNetworker.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * Networker + * + * @author william.liangf + */ +public interface ExchangeNetworker { + + /** + * lookup group. + * + * @param url group url + * @return group. + */ + ExchangeGroup lookup(URL url) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeNetworkers.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeNetworkers.java new file mode 100644 index 0000000000..8627608b5e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangeNetworkers.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; + +/** + * Networkers + * + * @author william.liangf + */ +public class ExchangeNetworkers { + + public static ExchangePeer join(String group, String peer, ExchangeHandler handler) throws RemotingException { + return join(URL.valueOf(group), URL.valueOf(peer), handler); + } + + public static ExchangePeer join(URL group, URL peer, ExchangeHandler handler) throws RemotingException { + return lookup(group).join(peer, handler); + } + + public static ExchangeGroup lookup(String group) throws RemotingException { + return lookup(URL.valueOf(group)); + } + + public static ExchangeGroup lookup(URL group) throws RemotingException { + ExchangeNetworker networker = ExtensionLoader.getExtensionLoader(ExchangeNetworker.class).getExtension(group.getProtocol()); + return networker.lookup(group); + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangePeer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangePeer.java new file mode 100644 index 0000000000..9a68b48dbe --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/ExchangePeer.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange; + +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.p2p.Peer; + +/** + * Peer + * + * @author william.liangf + */ +public interface ExchangePeer extends Peer, ExchangeServer { +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/AbstractExchangeGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/AbstractExchangeGroup.java new file mode 100644 index 0000000000..1a138ecace --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/AbstractExchangeGroup.java @@ -0,0 +1,125 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange.support; + +import java.util.ArrayList; +import java.util.Map; + +import org.jboss.netty.util.internal.ConcurrentHashMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerDispatcher; +import com.alibaba.dubbo.remoting.p2p.Peer; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangeGroup; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangePeer; + +/** + * AbstractGroup + * + * @author william.liangf + */ +public abstract class AbstractExchangeGroup implements ExchangeGroup { + + // 日志输出 + protected static final Logger logger = LoggerFactory.getLogger(AbstractExchangeGroup.class); + + protected final URL url; + + protected final Map servers = new ConcurrentHashMap(); + + protected final Map clients = new ConcurrentHashMap(); + + protected final ExchangeHandlerDispatcher dispatcher = new ExchangeHandlerDispatcher(); + + public AbstractExchangeGroup(URL url){ + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + this.url = url; + } + + public URL getUrl() { + return url; + } + + public void close() { + for (URL url : new ArrayList(servers.keySet())) { + try { + leave(url); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + for (URL url : new ArrayList(clients.keySet())) { + try { + disconnect(url); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + + public Peer join(URL url, ChannelHandler handler) throws RemotingException { + return join(url, (ExchangeHandler) handler); + } + + public ExchangePeer join(URL url, ExchangeHandler handler) throws RemotingException { + ExchangeServer server = servers.get(url); + if (server == null) { // TODO 有并发间隙 + server = Exchangers.bind(url, handler); + servers.put(url, server); + dispatcher.addChannelHandler(handler); + } + return new ExchangeServerPeer(server, clients, this); + } + + public void leave(URL url) throws RemotingException { + Server server = servers.remove(url); + if (server != null) { + server.close(); + } + } + + protected Client connect(URL url) throws RemotingException { + if (servers.containsKey(url)) { + return null; + } + ExchangeClient client = clients.get(url); + if (client == null) { // TODO 有并发间隙 + client = Exchangers.connect(url, dispatcher); + clients.put(url, client); + } + return client; + } + + protected void disconnect(URL url) throws RemotingException { + Client client = clients.remove(url); + if (client != null) { + client.close(); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/ExchangeServerPeer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/ExchangeServerPeer.java new file mode 100644 index 0000000000..09bef27c26 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/ExchangeServerPeer.java @@ -0,0 +1,137 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange.support; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeServerDelegate; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangeGroup; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangePeer; + +/** + * ServerPeer + * + * @author william.liangf + */ +public class ExchangeServerPeer extends ExchangeServerDelegate implements ExchangePeer { + + private static final Logger logger = LoggerFactory.getLogger(ExchangeServerPeer.class); + + private final Map clients; + + private final ExchangeGroup group; + + public ExchangeServerPeer(ExchangeServer server, Map clients, ExchangeGroup group){ + super(server); + this.clients = clients; + this.group = group; + } + + public void leave() throws RemotingException { + group.leave(getUrl()); + } + + @Override + public void close() { + try { + leave(); + } catch (RemotingException e) { + logger.error(e.getMessage(), e); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Collection getChannels() { + return (Collection) getExchangeChannels(); + } + + @Override + public Channel getChannel(InetSocketAddress remoteAddress) { + return getExchangeChannel(remoteAddress); + } + + @Override + public Collection getExchangeChannels() { + Collection channels = super.getExchangeChannels(); + if (clients.size() > 0) { + channels = channels == null ? new ArrayList() : new ArrayList(channels); + channels.addAll(clients.values()); + } + return channels; + } + + @Override + public ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress) { + String host = remoteAddress.getAddress() != null ? remoteAddress.getAddress().getHostAddress() : remoteAddress.getHostName(); + int port = remoteAddress.getPort(); + ExchangeChannel channel = super.getExchangeChannel(remoteAddress); + if (channel == null) { + for (Map.Entry entry : clients.entrySet()) { + URL url = entry.getKey(); + if (url.getHost().equals(host) && url.getPort() == port) { + return entry.getValue(); + } + } + } + return channel; + } + + @Override + public void send(Object message) throws RemotingException { + send(message, getUrl().getBooleanParameter(Constants.SENT_KEY)); + } + + @Override + public void send(Object message, boolean sent) throws RemotingException { + Throwable last = null; + try { + super.send(message, sent); + } catch (Throwable t) { + last = t; + } + for (Client client : clients.values()) { + try { + client.send(message, sent); + } catch (Throwable t) { + last = t; + } + } + if (last != null) { + if (last instanceof RemotingException) { + throw (RemotingException) last; + } else if (last instanceof RuntimeException) { + throw (RuntimeException) last; + } else { + throw new RuntimeException(last.getMessage(), last); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/FileExchangeGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/FileExchangeGroup.java new file mode 100644 index 0000000000..78856ac24e --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/FileExchangeGroup.java @@ -0,0 +1,138 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange.support; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.IOUtils; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangePeer; + +/** + * FileGroup + * + * @author william.liangf + */ +public class FileExchangeGroup extends AbstractExchangeGroup { + + private final File file; + + private volatile long last; + + // 定时任务执行器 + private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3, new NamedThreadFactory("FileGroupModifiedChecker", true)); + + // 重连定时器,定时检查连接是否可用,不可用时,无限次重连 + private final ScheduledFuture checkModifiedFuture; + + public FileExchangeGroup(URL url){ + super(url); + String path = url.getHost() + "/" + url.getPath(); + file = new File(path); + if (! file.exists()) { + throw new IllegalStateException("The group file not exists. file: " + path); + } + checkModifiedFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + public void run() { + // 检测文件变更 + try { + check(); + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at reconnect, cause: " + t.getMessage(), t); + } + } + }, 2000, 2000, TimeUnit.MILLISECONDS); + } + + public void close() { + super.close(); + try { + if (! checkModifiedFuture.isCancelled()) { + checkModifiedFuture.cancel(true); + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + + private void check() throws RemotingException { + long modified = file.lastModified(); + if (modified > last) { + last = modified; + changed(); + } + } + + private void changed() throws RemotingException { + try { + String[] lines = IOUtils.readLines(file); + for (String line : lines) { + connect(URL.valueOf(line)); + } + } catch (IOException e) { + throw new RemotingException(new InetSocketAddress(NetUtils.getLocalHost(), 0), getUrl().getInetSocketAddress(), e.getMessage(), e); + } + } + + public ExchangePeer joinExchange(URL url, ExchangeHandler handler) throws RemotingException { + ExchangePeer peer = super.join(url, handler); + try { + String full = url.toFullString(); + String[] lines = IOUtils.readLines(file); + for (String line : lines) { + if (full.equals(line)) { + return peer; + } + } + IOUtils.appendLines(file, new String[] {full}); + } catch (IOException e) { + throw new RemotingException(new InetSocketAddress(NetUtils.getLocalHost(), 0), getUrl().getInetSocketAddress(), e.getMessage(), e); + } + return peer; + } + + @Override + public void leave(URL url) throws RemotingException { + super.leave(url); + try { + String full = url.toFullString(); + String[] lines = IOUtils.readLines(file); + List saves = new ArrayList(); + for (String line : lines) { + if (full.equals(line)) { + return; + } + saves.add(line); + } + IOUtils.appendLines(file, saves.toArray(new String[0])); + } catch (IOException e) { + throw new RemotingException(new InetSocketAddress(NetUtils.getLocalHost(), 0), getUrl().getInetSocketAddress(), e.getMessage(), e); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/FileExchangeNetworker.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/FileExchangeNetworker.java new file mode 100644 index 0000000000..a5835ca6ef --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/FileExchangeNetworker.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangeGroup; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangeNetworker; + +/** + * FileNetworker + * + * @author william.liangf + */ +@Extension("file") +public class FileExchangeNetworker implements ExchangeNetworker { + + public ExchangeGroup lookup(URL url) throws RemotingException { + return new FileExchangeGroup(url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/MulticastExchangeGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/MulticastExchangeGroup.java new file mode 100644 index 0000000000..3850261dbb --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/MulticastExchangeGroup.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange.support; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangePeer; + +/** + * MulticastGroup + * + * @author william.liangf + */ +public class MulticastExchangeGroup extends AbstractExchangeGroup { + + private static final String JOIN = "join"; + + private static final String LEAVE = "leave"; + + private InetAddress mutilcastAddress; + + private MulticastSocket mutilcastSocket; + + public MulticastExchangeGroup(URL url) { + super(url); + if (! isMulticastAddress(url.getHost())) { + throw new IllegalArgumentException("Invalid multicast address " + url.getHost() + ", scope: 224.0.0.0 - 239.255.255.255"); + } + try { + mutilcastAddress = InetAddress.getByName(url.getHost()); + mutilcastSocket = new MulticastSocket(url.getPort()); + mutilcastSocket.setLoopbackMode(false); + mutilcastSocket.joinGroup(mutilcastAddress); + Thread thread = new Thread(new Runnable() { + public void run() { + byte[] buf = new byte[1024]; + DatagramPacket recv = new DatagramPacket(buf, buf.length); + while (true) { + try { + mutilcastSocket.receive(recv); + MulticastExchangeGroup.this.receive(new String(recv.getData()).trim(), (InetSocketAddress) recv.getSocketAddress()); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + }, "MulticastGroupReceiver"); + thread.setDaemon(true); + thread.start(); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + private static boolean isMulticastAddress(String ip) { + int i = ip.indexOf('.'); + if (i > 0) { + String prefix = ip.substring(0, i); + if (StringUtils.isInteger(prefix)) { + int p = Integer.parseInt(prefix); + return p >= 224 && p <= 239; + } + } + return false; + } + + private void send(String msg) throws RemotingException { + DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), mutilcastAddress, mutilcastSocket.getLocalPort()); + try { + mutilcastSocket.send(hi); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + private void receive(String msg, InetSocketAddress remoteAddress) throws RemotingException { + if (msg.startsWith(JOIN)) { + String url = msg.substring(JOIN.length()).trim(); + connect(URL.valueOf(url)); + } else if (msg.startsWith(LEAVE)) { + String url = msg.substring(LEAVE.length()).trim(); + disconnect(URL.valueOf(url)); + } + } + + @Override + public ExchangePeer join(URL url, ExchangeHandler handler) throws RemotingException { + ExchangePeer peer = super.join(url, handler); + send(JOIN + " " + url.toFullString()); + return peer; + } + + @Override + public void leave(URL url) throws RemotingException { + super.leave(url); + send(LEAVE + " " + url.toFullString()); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/MulticastExchangeNetworker.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/MulticastExchangeNetworker.java new file mode 100644 index 0000000000..3cd808e28b --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/exchange/support/MulticastExchangeNetworker.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.exchange.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangeGroup; +import com.alibaba.dubbo.remoting.p2p.exchange.ExchangeNetworker; + +/** + * MulticastNetworker + * + * @author william.liangf + */ +@Extension("multicast") +public class MulticastExchangeNetworker implements ExchangeNetworker { + + public ExchangeGroup lookup(URL url) throws RemotingException { + return new MulticastExchangeGroup(url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/AbstractGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/AbstractGroup.java new file mode 100644 index 0000000000..a7c732dccd --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/AbstractGroup.java @@ -0,0 +1,117 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.support; + +import java.util.ArrayList; +import java.util.Map; + +import org.jboss.netty.util.internal.ConcurrentHashMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.Transporters; +import com.alibaba.dubbo.remoting.p2p.Group; +import com.alibaba.dubbo.remoting.p2p.Peer; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerDispatcher; + +/** + * AbstractGroup + * + * @author william.liangf + */ +public abstract class AbstractGroup implements Group { + + // 日志输出 + protected static final Logger logger = LoggerFactory.getLogger(AbstractGroup.class); + + protected final URL url; + + protected final Map servers = new ConcurrentHashMap(); + + protected final Map clients = new ConcurrentHashMap(); + + protected final ChannelHandlerDispatcher dispatcher = new ChannelHandlerDispatcher(); + + public AbstractGroup(URL url){ + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + this.url = url; + } + + public URL getUrl() { + return url; + } + + public void close() { + for (URL url : new ArrayList(servers.keySet())) { + try { + leave(url); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + for (URL url : new ArrayList(clients.keySet())) { + try { + disconnect(url); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + + public Peer join(URL url, ChannelHandler handler) throws RemotingException { + Server server = servers.get(url); + if (server == null) { // TODO 有并发间隙 + server = Transporters.bind(url, handler); + servers.put(url, server); + dispatcher.addChannelHandler(handler); + } + return new ServerPeer(server, clients, this); + } + + public void leave(URL url) throws RemotingException { + Server server = servers.remove(url); + if (server != null) { + server.close(); + } + } + + protected Client connect(URL url) throws RemotingException { + if (servers.containsKey(url)) { + return null; + } + Client client = clients.get(url); + if (client == null) { // TODO 有并发间隙 + client = Transporters.connect(url, dispatcher); + clients.put(url, client); + } + return client; + } + + protected void disconnect(URL url) throws RemotingException { + Client client = clients.remove(url); + if (client != null) { + client.close(); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/FileGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/FileGroup.java new file mode 100644 index 0000000000..5ba6f459f4 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/FileGroup.java @@ -0,0 +1,135 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.support; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.IOUtils; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.p2p.Peer; + +/** + * FileGroup + * + * @author william.liangf + */ +public class FileGroup extends AbstractGroup { + + private final File file; + + private volatile long last; + + // 定时任务执行器 + private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3, new NamedThreadFactory("FileGroupModifiedChecker", true)); + + // 重连定时器,定时检查连接是否可用,不可用时,无限次重连 + private final ScheduledFuture checkModifiedFuture; + + public FileGroup(URL url){ + super(url); + String path = url.getAbsolutePath(); + file = new File(path); + checkModifiedFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { + public void run() { + // 检测文件变更 + try { + check(); + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at reconnect, cause: " + t.getMessage(), t); + } + } + }, 2000, 2000, TimeUnit.MILLISECONDS); + } + + public void close() { + super.close(); + try { + if (! checkModifiedFuture.isCancelled()) { + checkModifiedFuture.cancel(true); + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + + private void check() throws RemotingException { + long modified = file.lastModified(); + if (modified > last) { + last = modified; + changed(); + } + } + + private void changed() throws RemotingException { + try { + String[] lines = IOUtils.readLines(file); + for (String line : lines) { + connect(URL.valueOf(line)); + } + } catch (IOException e) { + throw new RemotingException(new InetSocketAddress(NetUtils.getLocalHost(), 0), getUrl().getInetSocketAddress(), e.getMessage(), e); + } + } + + public Peer join(URL url, ChannelHandler handler) throws RemotingException { + Peer peer = super.join(url, handler); + try { + String full = url.toFullString(); + String[] lines = IOUtils.readLines(file); + for (String line : lines) { + if (full.equals(line)) { + return peer; + } + } + IOUtils.appendLines(file, new String[] {full}); + } catch (IOException e) { + throw new RemotingException(new InetSocketAddress(NetUtils.getLocalHost(), 0), getUrl().getInetSocketAddress(), e.getMessage(), e); + } + return peer; + } + + @Override + public void leave(URL url) throws RemotingException { + super.leave(url); + try { + String full = url.toFullString(); + String[] lines = IOUtils.readLines(file); + List saves = new ArrayList(); + for (String line : lines) { + if (full.equals(line)) { + return; + } + saves.add(line); + } + IOUtils.appendLines(file, saves.toArray(new String[0])); + } catch (IOException e) { + throw new RemotingException(new InetSocketAddress(NetUtils.getLocalHost(), 0), getUrl().getInetSocketAddress(), e.getMessage(), e); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/FileNetworker.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/FileNetworker.java new file mode 100644 index 0000000000..6998a4a16b --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/FileNetworker.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.p2p.Group; +import com.alibaba.dubbo.remoting.p2p.Networker; + +/** + * FileNetworker + * + * @author william.liangf + */ +@Extension("file") +public class FileNetworker implements Networker { + + public Group lookup(URL url) throws RemotingException { + return new FileGroup(url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/MulticastGroup.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/MulticastGroup.java new file mode 100644 index 0000000000..beca3ba9c9 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/MulticastGroup.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.support; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.p2p.Peer; + +/** + * MulticastGroup + * + * @author william.liangf + */ +public class MulticastGroup extends AbstractGroup { + + private static final String JOIN = "join"; + + private static final String LEAVE = "leave"; + + private InetAddress mutilcastAddress; + + private MulticastSocket mutilcastSocket; + + public MulticastGroup(URL url) { + super(url); + if (! isMulticastAddress(url.getHost())) { + throw new IllegalArgumentException("Invalid multicast address " + url.getHost() + ", scope: 224.0.0.0 - 239.255.255.255"); + } + try { + mutilcastAddress = InetAddress.getByName(url.getHost()); + mutilcastSocket = new MulticastSocket(url.getPort()); + mutilcastSocket.setLoopbackMode(false); + mutilcastSocket.joinGroup(mutilcastAddress); + Thread thread = new Thread(new Runnable() { + public void run() { + byte[] buf = new byte[1024]; + DatagramPacket recv = new DatagramPacket(buf, buf.length); + while (true) { + try { + mutilcastSocket.receive(recv); + MulticastGroup.this.receive(new String(recv.getData()).trim(), (InetSocketAddress) recv.getSocketAddress()); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + }, "MulticastGroupReceiver"); + thread.setDaemon(true); + thread.start(); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + private static boolean isMulticastAddress(String ip) { + int i = ip.indexOf('.'); + if (i > 0) { + String prefix = ip.substring(0, i); + if (StringUtils.isInteger(prefix)) { + int p = Integer.parseInt(prefix); + return p >= 224 && p <= 239; + } + } + return false; + } + + private void send(String msg) throws RemotingException { + DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), mutilcastAddress, mutilcastSocket.getLocalPort()); + try { + mutilcastSocket.send(hi); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + private void receive(String msg, InetSocketAddress remoteAddress) throws RemotingException { + if (msg.startsWith(JOIN)) { + String url = msg.substring(JOIN.length()).trim(); + connect(URL.valueOf(url)); + } else if (msg.startsWith(LEAVE)) { + String url = msg.substring(LEAVE.length()).trim(); + disconnect(URL.valueOf(url)); + } + } + + @Override + public Peer join(URL url, ChannelHandler handler) throws RemotingException { + Peer peer = super.join(url, handler); + send(JOIN + " " + url.toFullString()); + return peer; + } + + @Override + public void leave(URL url) throws RemotingException { + super.leave(url); + send(LEAVE + " " + url.toFullString()); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/MulticastNetworker.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/MulticastNetworker.java new file mode 100644 index 0000000000..caf2b3f390 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/MulticastNetworker.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.support; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.p2p.Group; +import com.alibaba.dubbo.remoting.p2p.Networker; + +/** + * MulticastNetworker + * + * @author william.liangf + */ +@Extension("multicast") +public class MulticastNetworker implements Networker { + + public Group lookup(URL url) throws RemotingException { + return new MulticastGroup(url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/ServerPeer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/ServerPeer.java new file mode 100644 index 0000000000..e4a23e1f46 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/p2p/support/ServerPeer.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.p2p.support; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.p2p.Group; +import com.alibaba.dubbo.remoting.p2p.Peer; +import com.alibaba.dubbo.remoting.transport.support.ServerDelegate; + +/** + * ServerPeer + * + * @author william.liangf + */ +public class ServerPeer extends ServerDelegate implements Peer { + + private static final Logger logger = LoggerFactory.getLogger(ServerPeer.class); + + private final Map clients; + + private final Group group; + + public ServerPeer(Server server, Map clients, Group group){ + super(server); + this.clients = clients; + this.group = group; + } + + public void leave() throws RemotingException { + group.leave(getUrl()); + } + + @Override + public void close() { + try { + leave(); + } catch (RemotingException e) { + logger.error(e.getMessage(), e); + } + } + + @Override + public Collection getChannels() { + Collection channels = super.getChannels(); + if (clients.size() > 0) { + channels = channels == null ? new ArrayList() : new ArrayList(channels); + channels.addAll(clients.values()); + } + return channels; + } + + @Override + public Channel getChannel(InetSocketAddress remoteAddress) { + String host = remoteAddress.getAddress() != null ? remoteAddress.getAddress().getHostAddress() : remoteAddress.getHostName(); + int port = remoteAddress.getPort(); + Channel channel = super.getChannel(remoteAddress); + if (channel == null) { + for (Map.Entry entry : clients.entrySet()) { + URL url = entry.getKey(); + if (url.getHost().equals(host) && url.getPort() == port) { + return entry.getValue(); + } + } + } + return channel; + } + + @Override + public void send(Object message) throws RemotingException { + send(message, getUrl().getBooleanParameter(Constants.SENT_KEY)); + } + + @Override + public void send(Object message, boolean sent) throws RemotingException { + Throwable last = null; + try { + super.send(message, sent); + } catch (Throwable t) { + last = t; + } + for (Client client : clients.values()) { + try { + client.send(message, sent); + } catch (Throwable t) { + last = t; + } + } + if (last != null) { + if (last instanceof RemotingException) { + throw (RemotingException) last; + } else if (last instanceof RuntimeException) { + throw (RuntimeException) last; + } else { + throw new RuntimeException(last.getMessage(), last); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/TelnetHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/TelnetHandler.java new file mode 100644 index 0000000000..cca6c56145 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/TelnetHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * TelnetHandler + * + * @author william.liangf + */ +@Extension +public interface TelnetHandler { + + /** + * telnet. + * + * @param channel + * @param message + */ + String telnet(Channel channel, String message) throws RemotingException; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/codec/TelnetCodec.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/codec/TelnetCodec.java new file mode 100644 index 0000000000..d1b463469b --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/codec/TelnetCodec.java @@ -0,0 +1,280 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.codec; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.codec.TransportCodec; + +/** + * TelnetCodec + * + * @author heyman + * @author william.liangf + * @author chao.liuc + */ +@Extension("telnet") +public class TelnetCodec extends TransportCodec { + + private static final Logger logger = LoggerFactory.getLogger(TelnetCodec.class); + + private static final String HISTORY_LIST_KEY = "telnet.history.list"; + + private static final String HISTORY_INDEX_KEY = "telnet.history.index"; + + private static final byte[] UP = new byte[] {27, 91, 65}; + + private static final byte[] DOWN = new byte[] {27, 91, 66}; + + private static final List ENTER = Arrays.asList(new Object[] { new byte[] { '\r', '\n' } /* Windows Enter */, new byte[] { '\n' } /* Linux Enter */ }); + + private static final List EXIT = Arrays.asList(new Object[] { new byte[] { 3 } /* Windows Ctrl+C */, new byte[] { -1, -12, -1, -3, 6 } /* Linux Ctrl+C */, new byte[] { -1, -19, -1, -3, 6 } /* Linux Pause */ }); + + public void encode(Channel channel, OutputStream output, Object message) throws IOException { + if (message instanceof String) { + if (isClientSide(channel)) { + message = message + "\r\n"; + } + byte[] msgData = ((String) message).getBytes(getCharset(channel).name()); + output.write(msgData); + output.flush(); + } else { + super.encode(channel, output, message); + } + } + + public Object decode(Channel channel, InputStream is) throws IOException { + int readable = is.available(); + byte[] message = new byte[readable]; + is.read(message); + return decode(channel, is, readable, message); + } + + @SuppressWarnings("unchecked") + protected Object decode(Channel channel, InputStream is, int readable, byte[] message) throws IOException { + if (isClientSide(channel)) { + return toString(message, getCharset(channel)); + } + checkPayload(channel, readable); + if (message == null || message.length == 0) { + return NEED_MORE_INPUT; + } + + if (message[message.length - 1] == '\b') { // Windows backspace echo + try { + boolean doublechar = message.length > 2 && message[message.length - 3] < 0; // double byte char + channel.send(new String(doublechar ? new byte[] {32, 32, 8, 8} : new byte[] {32, 8}, getCharset(channel).name())); + } catch (RemotingException e) { + throw new IOException(StringUtils.toString(e)); + } + return NEED_MORE_INPUT; + } + + for (Object command : EXIT) { + if (isEquals(message, (byte[]) command)) { + if (logger.isInfoEnabled()) { + logger.info(new Exception("Close channel " + channel + " on exit command " + command)); + } + channel.close(); + return null; + } + } + + boolean up = endsWith(message, UP); + boolean down = endsWith(message, DOWN); + if (up || down) { + LinkedList history = (LinkedList) channel.getAttribute(HISTORY_LIST_KEY); + if (history == null || history.size() == 0) { + return NEED_MORE_INPUT; + } + byte[] input = new byte[message.length - (up? UP.length:DOWN.length) ]; + System.arraycopy(message, 0, input, 0, input.length); + Integer currentIndex = (Integer) channel.getAttribute(HISTORY_INDEX_KEY); + Integer targetIndex = currentIndex; + if (currentIndex == null) { + currentIndex = history.size() - 1; + //first up need point to the last history item + targetIndex = history.size(); + } + if (up) { + if (targetIndex > 0 ){ + targetIndex = Math.min(targetIndex - 1, history.size() -1); + } + } else { + if (targetIndex < history.size() - 1){ + targetIndex = Math.min(targetIndex + 1, history.size() -1); + } + //else current input?? message-down + } + String value = history.get(targetIndex); + String out = getbackSpaceString(toString(input, getCharset(channel))); + value = out + value; + try { + channel.send(value); + } catch (RemotingException e) { + throw new IOException(StringUtils.toString(e)); + } + channel.setAttribute(HISTORY_INDEX_KEY, targetIndex); + return NEED_MORE_INPUT; + } else { + byte[] enter = null; + for (Object command : ENTER) { + if (endsWith(message, (byte[]) command)) { + enter = (byte[]) command; + break; + } + } + if (enter == null) { + return NEED_MORE_INPUT; + } + LinkedList history = (LinkedList) channel.getAttribute(HISTORY_LIST_KEY); + if (history == null ) { + //telnet ignore concurrent + history = new LinkedList(); + channel.setAttribute(HISTORY_LIST_KEY, history); + } + String result = toString(message, getCharset(channel)); + history.add(result); + return result; + } + + + } + private static String getbackSpaceString(String input){ + StringBuffer buf = new StringBuffer(input.length()*3); + for (int i = 0; i < input.length(); i ++) { + buf.append("\b"); + } + for (int i = 0; i < input.length(); i ++) { + buf.append(" "); + } + for (int i = 0; i < input.length(); i ++) { + buf.append("\b"); + } + buf.append(input); + return buf.toString(); + } + + private static boolean isClientSide(Channel channel) { + InetSocketAddress address = channel.getRemoteAddress(); + URL url = channel.getUrl(); + return url.getPort() == address.getPort() && + NetUtils.filterLocalHost(url.getHost()) + .equals(NetUtils.filterLocalHost(address.getAddress().getHostAddress())); + } + + private static Charset getCharset(Channel channel) { + if (channel != null) { + Object attribute = channel.getAttribute(Constants.CHARSET_KEY); + if (attribute instanceof String) { + try { + return Charset.forName((String) attribute); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } else if (attribute instanceof Charset) { + return (Charset) attribute; + } + URL url = channel.getUrl(); + if (url != null) { + String parameter = url.getParameter(Constants.CHARSET_KEY); + if (parameter != null && parameter.length() > 0) { + try { + return Charset.forName(parameter); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + } + try { + return Charset.forName("GBK"); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + return Charset.defaultCharset(); + } + + private static String toString(byte[] message, Charset charset) throws UnsupportedEncodingException { + byte[] copy = new byte[message.length]; + int index = 0; + for (int i = 0; i < message.length; i ++) { + byte b = message[i] ; + if (b == '\b') { // backspace + if (index > 0) { + index --; + } + if (i > 2 && message[i - 2] < 0) { // double byte char + if (index > 0) { + index --; + } + } + } else if (b == 27) { // escape + if (i < message.length - 4 && message[i + 4] == 126) { + i = i + 4; + } else if (i < message.length - 3 && message[i + 3] == 126) { + i = i + 3; + } else if (i < message.length - 2) { + i = i + 2; + } + } else if (b == -1 && i < message.length - 2 + && (message[i + 1] == -3 || message[i + 1] == -5)) { // handshake + i = i + 2; + } else { + copy[index ++] = message[i]; + } + } + if (index == 0) { + return ""; + } + return new String(copy, 0, index, charset.name()).trim(); + } + + private static boolean isEquals(byte[] message, byte[] command) throws IOException { + return message.length == command.length && endsWith(message, command); + } + + private static boolean endsWith(byte[] message, byte[] command) throws IOException { + if (message.length < command.length) { + return false; + } + int offset = message.length - command.length; + for (int i = command.length - 1; i >= 0 ; i --) { + if (message[offset + i] != command[i]) { + return false; + } + } + return true; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/Help.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/Help.java new file mode 100644 index 0000000000..8b6c1a936f --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/Help.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Help + * + * @author william.liangf + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface Help { + + String parameter() default ""; + + String summary(); + + String detail() default ""; + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java new file mode 100644 index 0000000000..15a94b1497 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java @@ -0,0 +1,80 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support; + +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerAdapter; + +/** + * TelnetHandlerDispather + * + * @author william.liangf + */ +public class TelnetHandlerAdapter extends ChannelHandlerAdapter implements TelnetHandler { + + public String telnet(Channel channel, String message) throws RemotingException { + String telnet = channel.getUrl().getParameter("telnet"); + String prompt = channel.getUrl().getParameter("prompt"); + List commands = ConfigUtils.mergeValues(TelnetHandler.class, telnet, Constants.DEFAULT_TELNET_COMMANDS); + StringBuilder buf = new StringBuilder(); + if (commands != null && commands.size() > 0) { + message = message.trim(); + String command; + if (message.length() > 0) { + int i = message.indexOf(' '); + if (i > 0) { + command = message.substring(0, i).trim(); + message = message.substring(i + 1).trim(); + } else { + command = message; + message = ""; + } + } else { + command = ""; + } + if (commands.contains(command)) { + TelnetHandler handler = ExtensionLoader.getExtensionLoader(TelnetHandler.class).getExtension(command); + try { + String result = handler.telnet(channel, message); + if (result != null) { + buf.append(result); + } + } catch (Throwable t) { + buf.append(t.getMessage()); + } + } else if (command.length() > 0) { + buf.append("Unsupported command: "); + buf.append(command); + } + if (buf.length() > 0) { + buf.append("\r\n"); + } + } + if (prompt != null && prompt.length() > 0) { + buf.append(prompt); + buf.append(">"); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/TelnetUtils.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/TelnetUtils.java new file mode 100644 index 0000000000..02aaa63812 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/TelnetUtils.java @@ -0,0 +1,160 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support; + +import java.util.Arrays; +import java.util.List; + +/** + * TelnetUtils + * + * @author william.liangf + */ +public class TelnetUtils { + + public static String toList(List> table) { + int[] widths = new int[table.get(0).size()]; + for (int j = 0; j < widths.length; j ++) { + for (List row : table) { + widths[j] = Math.max(widths[j], row.get(j).length()); + } + } + StringBuilder buf = new StringBuilder(); + for (List row : table) { + if (buf.length() > 0) { + buf.append("\r\n"); + } + for (int j = 0; j < widths.length; j ++) { + if (j > 0) { + buf.append(" - "); + } + String value = row.get(j); + buf.append(value); + if (j < widths.length - 1) { + int pad = widths[j] - value.length(); + if (pad > 0) { + for (int k = 0; k < pad; k ++) { + buf.append(" "); + } + } + } + } + } + return buf.toString(); + } + + public static String toTable(String[] header, List> table) { + return toTable(Arrays.asList(header), table); + } + + public static String toTable(List header, List> table) { + int totalWidth = 0 ; + int[] widths = new int[header.size()]; + int maxwidth = 70; + int maxcountbefore = 0; + for (int j = 0; j < widths.length; j ++) { + widths[j] = Math.max(widths[j], header.get(j).length()); + } + for (List row : table) { + int countbefore = 0; + for (int j = 0; j < widths.length; j ++) { + widths[j] = Math.max(widths[j], row.get(j).length() ); + totalWidth = (totalWidth + widths[j])> maxwidth ? maxwidth : (totalWidth + widths[j]); + if (j 0) { + for (int k = 0; k < pad; k ++) { + buf.append(" "); + } + } + buf.append(" |"); + } + buf.append("\r\n"); + //line + buf.append("+"); + for (int j = 0; j < widths.length; j ++) { + for (int k = 0; k < widths[j] + 2; k ++) { + buf.append("-"); + } + buf.append("+"); + } + buf.append("\r\n"); + //content + for (List row : table) { + StringBuffer rowbuf = new StringBuffer(); + rowbuf.append("|"); + for (int j = 0; j < widths.length; j ++) { + String cell = row.get(j); + rowbuf.append(" "); + int remaing = cell.length(); + while (remaing > 0){ + + if (rowbuf.length() >= totalWidth ){ + buf.append(rowbuf.toString()); + rowbuf = new StringBuffer(); +// for(int m = 0;m < maxcountbefore && maxcountbefore < totalWidth ; m++){ +// rowbuf.append(" "); +// } + } + + rowbuf.append(cell.substring(cell.length()-remaing, cell.length()-remaing +1)); + remaing -- ; + } + int pad = widths[j] - cell.length(); + if (pad > 0) { + for (int k = 0; k < pad; k ++) { + rowbuf.append(" "); + } + } + rowbuf.append(" |"); + } + buf.append(rowbuf).append("\r\n"); + } + //line + buf.append("+"); + for (int j = 0; j < widths.length; j ++) { + for (int k = 0; k < widths[j] + 2; k ++) { + buf.append("-"); + } + buf.append("+"); + } + buf.append("\r\n"); + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java new file mode 100644 index 0000000000..a87d0502f9 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support.command; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; + +/** + * ClearTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[lines]", summary = "Clear screen.", detail = "Clear screen.") +@Extension("clear") +public class ClearTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + int lines = 100; + if (message.length() > 0) { + if (! StringUtils.isInteger(message)) { + return "Illegal lines " + message + ", must be integer."; + } + lines = Integer.parseInt(message); + } + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < lines; i ++) { + buf.append("\r\n"); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/ExitTelnetHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/ExitTelnetHandler.java new file mode 100644 index 0000000000..ce933e3ed9 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/ExitTelnetHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support.command; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; + +/** + * ExitTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "", summary = "Exit the telnet.", detail = "Exit the telnet.") +@Extension("exit") +public class ExitTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + channel.close(); + return null; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/HelpTelnetHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/HelpTelnetHandler.java new file mode 100644 index 0000000000..4903eeba4d --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/HelpTelnetHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support.command; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.remoting.telnet.support.TelnetUtils; + +/** + * HelpTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[command]", summary = "Show help.", detail = "Show help.") +@Extension("help") +public class HelpTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + if (message.length() > 0) { + if (! ExtensionLoader.getExtensionLoader(TelnetHandler.class).hasExtension(message)) { + return "No such command " + message; + } + TelnetHandler handler = ExtensionLoader.getExtensionLoader(TelnetHandler.class).getExtension(message); + Help help = handler.getClass().getAnnotation(Help.class); + StringBuilder buf = new StringBuilder(); + buf.append("Command:\r\n "); + buf.append(message + " " + help.parameter().replace("\r\n", " ").replace("\n", " ")); + buf.append("\r\nSummary:\r\n "); + buf.append(help.summary().replace("\r\n", " ").replace("\n", " ")); + buf.append("\r\nDetail:\r\n "); + buf.append(help.detail().replace("\r\n", " \r\n").replace("\n", " \n")); + return buf.toString(); + } else { + List> table = new ArrayList>(); + String telnet = channel.getUrl().getParameter("telnet"); + if (telnet != null && telnet.length() > 0) { + for (String cmd : Constants.COMMA_SPLIT_PATTERN.split(telnet)) { + TelnetHandler handler = ExtensionLoader.getExtensionLoader(TelnetHandler.class).getExtension(cmd); + Help help = handler.getClass().getAnnotation(Help.class); + List row = new ArrayList(); + String parameter = " " + cmd + " " + (help != null ? help.parameter().replace("\r\n", " ").replace("\n", " ") : ""); + row.add(parameter.length() > 50 ? parameter.substring(0, 50) + "..." : parameter); + String summary = help != null ? help.summary().replace("\r\n", " ").replace("\n", " ") : ""; + row.add(summary.length() > 50 ? summary.substring(0, 50) + "..." : summary); + table.add(row); + } + } + return "Please input \"help [command]\" show detail.\r\n" + TelnetUtils.toList(table); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java new file mode 100644 index 0000000000..164db61a08 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.telnet.support.command; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.common.status.support.StatusUtils; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.remoting.telnet.support.TelnetUtils; + +/** + * StatusTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[-l]", summary = "Show status.", detail = "Show status.") +@Extension("status") +public class StatusTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + if (message.equals("-l")) { + String status = channel.getUrl().getParameter("status"); + List ss = ConfigUtils.mergeValues(StatusChecker.class, status, Constants.DEFAULT_CHECK_STATUSES); + String[] header = new String[] {"resource", "status", "message"}; + List> table = new ArrayList>(); + Map statuses = new HashMap(); + if (ss != null && ss.size() > 0) { + for (String s : ss) { + StatusChecker handler = ExtensionLoader.getExtensionLoader(StatusChecker.class).getExtension(s); + Status stat; + try { + stat = handler.check(); + } catch (Throwable t) { + stat = new Status(Status.Level.ERROR, t.getMessage()); + } + statuses.put(s, stat); + if (stat.getLevel() != null && stat.getLevel() != Status.Level.UNKNOWN) { + List row = new ArrayList(); + row.add(s); + row.add(String.valueOf(stat.getLevel())); + row.add(stat.getMessage() == null ? "" : stat.getMessage()); + table.add(row); + } + } + } + Status stat= StatusUtils.getSummaryStatus(statuses); + List row = new ArrayList(); + row.add("summary"); + row.add(String.valueOf(stat.getLevel())); + row.add(stat.getMessage()); + table.add(row); + return TelnetUtils.toTable(header, table); + } else if (message.length() > 0) { + return "Unsupported parameter " + message + " for status."; + } + String status = channel.getUrl().getParameter("status"); + Map statuses = new HashMap(); + if (status != null && status.length() > 0) { + String[] ss = Constants.COMMA_SPLIT_PATTERN.split(status); + for (String s : ss) { + StatusChecker handler = ExtensionLoader.getExtensionLoader(StatusChecker.class).getExtension(s); + Status stat; + try { + stat = handler.check(); + } catch (Throwable t) { + stat = new Status(Status.Level.ERROR, t.getMessage()); + } + statuses.put(s, stat); + } + } + Status stat= StatusUtils.getSummaryStatus(statuses); + return String.valueOf(stat.getLevel()); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/codec/TransportCodec.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/codec/TransportCodec.java new file mode 100644 index 0000000000..beffa852ea --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/codec/TransportCodec.java @@ -0,0 +1,66 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.codec; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.transport.support.AbstractCodec; + +/** + * TransportCodec + * + * @author william.liangf + */ +@Extension("transport") +public class TransportCodec extends AbstractCodec { + + public void encode(Channel channel, OutputStream output, Object message) throws IOException { + ObjectOutput objectOutput = getSerialization(channel).serialize(channel.getUrl(), output); + encodeData(channel, objectOutput, message); + objectOutput.flushBuffer(); + } + + public Object decode(Channel channel, InputStream input) throws IOException { + return decodeData(channel, getSerialization(channel).deserialize(channel.getUrl(), input)); + } + + protected void encodeData(Channel channel, ObjectOutput output, Object message) throws IOException { + encodeData(output, message); + } + + protected Object decodeData(Channel channel, ObjectInput input) throws IOException { + return decodeData(input); + } + + protected void encodeData(ObjectOutput output, Object message) throws IOException { + output.writeObject(message); + } + + protected Object decodeData(ObjectInput input) throws IOException { + try { + return input.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException("ClassNotFoundException: " + StringUtils.toString(e)); + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractChannel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractChannel.java new file mode 100644 index 0000000000..c5969b7c39 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractChannel.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * AbstractChannel + * + * @author william.liangf + */ +public abstract class AbstractChannel extends AbstractPeer implements Channel { + + public AbstractChannel(URL url, ChannelHandler handler){ + super(url, handler); + } + + public void send(Object message, boolean sent) throws RemotingException { + if (isClosed()) { + throw new RemotingException(this, "Failed to send message " + + (message == null ? "" : message.getClass().getName()) + ":" + message + + ", cause: Channel closed. channel: " + getLocalAddress() + " -> " + getRemoteAddress()); + } + } + + @Override + public String toString() { + return getLocalAddress() + " -> " + getRemoteAddress(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractClient.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractClient.java new file mode 100644 index 0000000000..d5d29554d1 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractClient.java @@ -0,0 +1,337 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.ExecutorUtil; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.WrappedChannelHandler; + +/** + * AbstractClient + * + * @author qian.lei + * @author chao.liuc + */ +public abstract class AbstractClient extends AbstractEndpoint implements Client { + + protected static final String CLIENT_THREAD_POOL_NAME ="DubboClientHandler"; + + private static final AtomicInteger CLIENT_THREAD_POOL_ID = new AtomicInteger(); + + private final Lock connectLock = new ReentrantLock(); + + private static final ScheduledThreadPoolExecutor reconnectExecutorService = new ScheduledThreadPoolExecutor(2, new NamedThreadFactory("client-connect-check-timer", true)); + + private volatile ScheduledFuture reconnectExecutorFuture = null; + + protected volatile ExecutorService executor; + + private final boolean send_reconnect ; + + + public AbstractClient(URL url, ChannelHandler handler) throws RemotingException { + super(url, handler); + + send_reconnect = url.getBooleanParameter(Constants.SEND_RECONNECT_KEY, false); + + try { + doOpen(); + } catch (Throwable t) { + close(); + throw new RemotingException(url.getInetSocketAddress(), null, + "Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() + + " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t); + } + try { + // connect. + connect(); + if (logger.isInfoEnabled()) { + logger.info("Start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() + " connect to the server " + getRemoteAddress()); + } + } catch (RemotingException t) { + if (url.getBooleanParameter(Constants.CHECK_KEY, true)) { + close(); + throw t; + } else { + logger.error("Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() + + " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t); + } + } catch (Throwable t){ + close(); + throw new RemotingException(url.getInetSocketAddress(), null, + "Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress() + + " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t); + } + + if (handler instanceof WrappedChannelHandler ){ + executor = ((WrappedChannelHandler)handler).getExecutor(); + } + } + + /** + * init reconnect thread + */ + private synchronized void initConnectStatusCheckCommand(){ + //如果配置了 reconnect = false 则不尝试重连。 + int reconnect = getReconnectParam(getUrl()); + if(reconnect > 0 && reconnectExecutorFuture == null){ + Runnable connectStatusCheckCommand = new Runnable() { + public void run() { + try { + if (! isConnected()) { + connect();//定时检查与消息发送时检测都要做。 + } + } catch (Throwable t) { // 防御性容错 + logger.error("Unexpected error occur at client reconnect", t); + } + } + }; + reconnectExecutorFuture = reconnectExecutorService.scheduleWithFixedDelay(connectStatusCheckCommand, reconnect, reconnect, TimeUnit.MILLISECONDS); + } + } + + /** + * @param url + * @return 0-false + */ + private static int getReconnectParam(URL url){ + int reconnect ; + String param = url.getParameter(Constants.RECONNECT_KEY); + if (param == null || param.length()==0 || "true".equalsIgnoreCase(param)){ + reconnect = Constants.DEFAULT_RECONNECT_PERIOD; + }else if ("false".equalsIgnoreCase(param)){ + reconnect = 0; + } else { + try{ + reconnect = Integer.parseInt(param); + }catch (Exception e) { + throw new IllegalArgumentException("reconnect param must be nonnegative integer or false/true. input is:"+param); + } + if(reconnect < 0){ + throw new IllegalArgumentException("reconnect param must be nonnegative integer or false/true. input is:"+param); + } + } + return reconnect; + } + + private synchronized void destroyConnectStatusCheckCommand(){ + try { + if (reconnectExecutorFuture != null && ! reconnectExecutorFuture.isDone()){ + reconnectExecutorFuture.cancel(true); + reconnectExecutorService.purge(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + protected ExecutorService createExecutor() { + return Executors.newCachedThreadPool(new NamedThreadFactory(CLIENT_THREAD_POOL_NAME + CLIENT_THREAD_POOL_ID.incrementAndGet() + "-" + getUrl().getAddress(), true)); + } + + public InetSocketAddress getConnectAddress() { + return new InetSocketAddress(NetUtils.filterLocalHost(getUrl().getHost()), getUrl().getPort()); + } + + public InetSocketAddress getRemoteAddress() { + Channel channel = getChannel(); + if (channel == null) + return getUrl().getInetSocketAddress(); + return channel.getRemoteAddress(); + } + + public InetSocketAddress getLocalAddress() { + Channel channel = getChannel(); + if (channel == null) + return InetSocketAddress.createUnresolved(NetUtils.getLocalHost(), 0); + return channel.getLocalAddress(); + } + + public boolean isConnected() { + Channel channel = getChannel(); + if (channel == null) + return false; + return channel.isConnected(); + } + + public Object getAttribute(String key) { + Channel channel = getChannel(); + if (channel == null) + return null; + return channel.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + Channel channel = getChannel(); + if (channel == null) + return; + channel.setAttribute(key, value); + } + + public void removeAttribute(String key) { + Channel channel = getChannel(); + if (channel == null) + return; + channel.removeAttribute(key); + } + + public boolean hasAttribute(String key) { + Channel channel = getChannel(); + if (channel == null) + return false; + return channel.hasAttribute(key); + } + + public void send(Object message, boolean sent) throws RemotingException { + if (send_reconnect && !isConnected()){ + connect(); + } + Channel channel = getChannel(); + if (channel == null || ! channel.isConnected()) { + throw new RemotingException(this, channel == null ? "channel is null " : (" channel is closed ") +". url:" + getUrl()); + } + channel.send(message, sent); + } + + private void connect() throws RemotingException { + connectLock.lock(); + try { + if (isConnected()) { + return; + } + initConnectStatusCheckCommand(); + doConnect(); + if (! isConnected()) { + throw new RemotingException(this, "Failed connect to server " + getRemoteAddress() + " from " + getClass().getSimpleName() + + NetUtils.getLocalHost() + " using dubbo version " + Version.getVersion() + + ", cause: Connect wait timeout: " + getTimeout() + "ms."); + } + } catch (RemotingException e) { + throw e; + } catch (Throwable e) { + throw new RemotingException(this, "Failed connect to server " + getRemoteAddress() + " from " + getClass().getSimpleName() + + NetUtils.getLocalHost() + " using dubbo version " + Version.getVersion() + + ", cause: " + e.getMessage(), e); + } finally { + connectLock.unlock(); + } + } + + public void disconnect() { + connectLock.lock(); + try { + destroyConnectStatusCheckCommand(); + try { + Channel channel = getChannel(); + if (channel != null) { + channel.close(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + try { + doDisConnect(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } finally { + connectLock.unlock(); + } + } + + public void reconnect() throws RemotingException { + disconnect(); + connect(); + } + public void close() { + ExecutorUtil.shutdownNow(executor, 100); + try { + super.close(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + disconnect(); + try { + doClose(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + public void close(int timeout) { + ExecutorUtil.gracefulShutdown(executor ,timeout); + close(); + } + + @Override + public String toString() { + return getClass().getName() + " [" + getLocalAddress() + " -> " + getRemoteAddress() + "]"; + } + + /** + * Open client. + * + * @throws Throwable + */ + protected abstract void doOpen() throws Throwable; + + /** + * Close client. + * + * @throws Throwable + */ + protected abstract void doClose() throws Throwable; + + /** + * Connect to server. + * + * @throws Throwable + */ + protected abstract void doConnect() throws Throwable; + + /** + * disConnect to server. + * + * @throws Throwable + */ + protected abstract void doDisConnect() throws Throwable; + + /** + * Get the connected channel. + * + * @return channel + */ + protected abstract Channel getChannel(); + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractCodec.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractCodec.java new file mode 100644 index 0000000000..bd7af658eb --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractCodec.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.io.IOException; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.Codec; + +/** + * AbstractCodec + * + * @author william.liangf + */ +public abstract class AbstractCodec implements Codec { + + protected Serialization getSerialization(Channel channel) { + Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(channel.getUrl().getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION)); + return serialization; + } + + protected void checkPayload(Channel channel, long size) throws IOException { + int payload = Constants.DEFAULT_PAYLOAD; + if (channel != null && channel.getUrl() != null) { + payload = channel.getUrl().getPositiveIntParameter(Constants.PAYLOAD_KEY, Constants.DEFAULT_PAYLOAD); + } + if (size > payload) { + throw new IOException("Data length too large: " + size + ", max payload: " + payload + ", channel: " + channel); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractEndpoint.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractEndpoint.java new file mode 100644 index 0000000000..c04026f9b6 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractEndpoint.java @@ -0,0 +1,92 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.Resetable; + +/** + * AbstractEndpoint + * + * @author william.liangf + */ +public abstract class AbstractEndpoint extends AbstractPeer implements Resetable { + + private Codec codec; + + private int timeout; + + private int connectTimeout; + + public AbstractEndpoint(URL url, ChannelHandler handler) { + super(url, handler); + this.codec = ExtensionLoader.getExtensionLoader(Codec.class).getExtension(url.getParameter(Constants.CODEC_KEY, "telnet")); + this.timeout = url.getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + this.connectTimeout = url.getPositiveIntParameter(Constants.CONNECT_TIMEOUT_KEY, timeout); + } + + public void reset(URL url) { + if (isClosed()) { + throw new IllegalStateException("Failed to reset parameters " + + url + ", cause: Channel closed. channel: " + getLocalAddress()); + } + try { + if (url.hasParameter(Constants.HEARTBEAT_KEY)) { + int t = url.getIntParameter(Constants.TIMEOUT_KEY); + if (t > 0) { + this.timeout = t; + } + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + try { + if (url.hasParameter(Constants.CONNECT_TIMEOUT_KEY)) { + int t = url.getIntParameter(Constants.CONNECT_TIMEOUT_KEY); + if (t > 0) { + this.connectTimeout = t; + } + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + try { + if (url.hasParameter(Constants.CODEC_KEY)) { + String c = url.getParameter(Constants.CODEC_KEY); + this.codec = ExtensionLoader.getExtensionLoader(Codec.class).getExtension(c); + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + + protected Codec getCodec() { + return codec; + } + + protected int getTimeout() { + return timeout; + } + + protected int getConnectTimeout() { + return connectTimeout; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractPeer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractPeer.java new file mode 100644 index 0000000000..4d4e26c31c --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractPeer.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.io.IOException; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Endpoint; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * AbstractPeer + * + * @author qian.lei + * @author william.liangf + */ +public abstract class AbstractPeer implements Endpoint, ChannelHandler { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ChannelHandler handler; + + private volatile URL url; + + private volatile boolean closed; + + public AbstractPeer(URL url, ChannelHandler handler) { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + if (handler == null) { + throw new IllegalArgumentException("handler == null"); + } + this.url = url; + this.handler = handler; + } + + public void send(Object message) throws RemotingException { + send(message, url.getBooleanParameter(Constants.SENT_KEY)); + } + + public void close() { + closed = true; + } + public void close(int timeout) { + close(); + } + + public URL getUrl() { + return url; + } + + protected void setUrl(URL url) { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + this.url = url; + } + + public ChannelHandler getChannelHandler() { + return handler; + } + + public boolean isClosed() { + return closed; + } + + public void connected(Channel ch) throws RemotingException { + if (closed) { + return; + } + handler.connected(ch); + } + + public void disconnected(Channel ch) throws RemotingException { + handler.disconnected(ch); + } + + public void sent(Channel ch, Object msg) throws RemotingException { + if (closed) { + return; + } + handler.sent(ch, msg); + } + + public void received(Channel ch, Object msg) throws RemotingException { + if (closed) { + return; + } + handler.received(ch, msg); + } + + public void caught(Channel ch, Throwable ex) throws RemotingException { + if (ex instanceof IOException || ex instanceof RemotingException) { + logger.warn("IOException on channel " + ch, ex); + } else { + logger.error("Exception on channel " + ch, ex); + } + handler.caught(ch, ex); + } + + public ChannelHandler getHandler() { + return handler; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractServer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractServer.java new file mode 100644 index 0000000000..e11cee1317 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/AbstractServer.java @@ -0,0 +1,204 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.ExecutorUtil; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.transport.support.handler.WrappedChannelHandler; + +/** + * AbstractServer + * + * @author qian.lei + * @author ding.lid + */ +public abstract class AbstractServer extends AbstractEndpoint implements Server { + + private InetSocketAddress localAddress; + + private InetSocketAddress bindAddress; + + private int accepts; + + private int idleTimeout = 600; //600 seconds + + protected static final String SERVER_THREAD_POOL_NAME ="DubboServerHandler"; + + ExecutorService executor; + + public AbstractServer(URL url, ChannelHandler handler) throws RemotingException { + super(url, handler); + localAddress = getUrl().getInetSocketAddress(); + String host = url.getBooleanParameter(Constants.ANYHOST_KEY) + || NetUtils.isInvalidLocalHost(getUrl().getHost()) + ? NetUtils.ANYHOST : getUrl().getHost(); + bindAddress = new InetSocketAddress(host, getUrl().getPort()); + this.accepts = url.getIntParameter(Constants.ACCEPTS_KEY, Constants.DEFAULT_ACCEPTS); + this.idleTimeout = url.getIntParameter(Constants.IDLE_TIMEOUT_KEY, Constants.DEFAULT_IDLE_TIMEOUT); + try { + doOpen(); + if (logger.isInfoEnabled()) { + logger.info("Start " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress()); + } + } catch (Throwable t) { + throw new RemotingException(url.getInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName() + + " on " + getLocalAddress() + ", cause: " + t.getMessage(), t); + } + if (handler instanceof WrappedChannelHandler ){ + executor = ((WrappedChannelHandler)handler).getExecutor(); + } + } + + protected abstract void doOpen() throws Throwable; + + protected abstract void doClose() throws Throwable; + + public void reset(URL url) { + if (url == null) { + return; + } + try { + if (url.hasParameter(Constants.ACCEPTS_KEY)) { + int a = url.getIntParameter(Constants.ACCEPTS_KEY); + if (a > 0) { + this.accepts = a; + } + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + try { + if (url.hasParameter(Constants.IDLE_TIMEOUT_KEY)) { + int t = url.getIntParameter(Constants.IDLE_TIMEOUT_KEY); + if (t > 0) { + this.idleTimeout = t; + } + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + try { + if (url.hasParameter(Constants.THREADS_KEY) + && executor instanceof ThreadPoolExecutor && !executor.isShutdown()) { + ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; + int threads = url.getIntParameter(Constants.THREADS_KEY); + int max = threadPoolExecutor.getMaximumPoolSize(); + int core = threadPoolExecutor.getCorePoolSize(); + if (threads > 0 && (threads != max || threads != core)) { + if (threads < core) { + threadPoolExecutor.setCorePoolSize(threads); + if (core == max) { + threadPoolExecutor.setMaximumPoolSize(threads); + } + } else { + threadPoolExecutor.setMaximumPoolSize(threads); + if (core == max) { + threadPoolExecutor.setCorePoolSize(threads); + } + } + } + } + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + super.setUrl(getUrl().addParameters(url.getParameters())); + } + + public void send(Object message, boolean sent) throws RemotingException { + Collection channels = getChannels(); + for (Channel channel : channels) { + channel.send(message, sent); + } + } + + public void close() { + ExecutorUtil.shutdownNow(executor ,100); + try { + super.close(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + try { + doClose(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + public void close(int timeout) { + ExecutorUtil.gracefulShutdown(executor ,timeout); + close(); + } + + public InetSocketAddress getLocalAddress() { + return localAddress; + } + + public InetSocketAddress getBindAddress() { + return bindAddress; + } + + public int getAccepts() { + return accepts; + } + + public int getIdleTimeout() { + return idleTimeout; + } + + @Override + public void connected(Channel ch) throws RemotingException { + Collection channels = getChannels(); + if (accepts > 0 && channels.size() > accepts) { + logger.error("Close channel " + ch + ", cause: The server " + ch.getLocalAddress() + " connections greater than max config " + accepts); + ch.close(); + return; + } + super.connected(ch); + } + + @Override + public void disconnected(Channel ch) throws RemotingException { + Collection channels = getChannels(); + if (channels.size() == 0){ + logger.warn("All clients has discontected from " + ch.getLocalAddress() + ". You can graceful shutdown now."); + } + super.disconnected(ch); + } + + protected Codec getDownstreamCodec() { + Codec downstreamCodec = getCodec(); + String downstreamCodecStr = getUrl().getParameter(Constants.DOWNSTREAM_CODEC_KEY); + if(downstreamCodecStr != null ){ + downstreamCodec = ExtensionLoader.getExtensionLoader(Codec.class).getExtension(downstreamCodecStr); + } + return downstreamCodec; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelDelegate.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelDelegate.java new file mode 100644 index 0000000000..f16015a763 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelDelegate.java @@ -0,0 +1,107 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * ChannelDelegate + * + * @author william.liangf + */ +public class ChannelDelegate implements Channel { + + private transient Channel channel; + + public ChannelDelegate() { + } + + public ChannelDelegate(Channel channel) { + setChannel(channel); + } + + public Channel getChannel() { + return channel; + } + + public void setChannel(Channel channel) { + if (channel == null) { + throw new IllegalArgumentException("channel == null"); + } + this.channel = channel; + } + + public URL getUrl() { + return channel.getUrl(); + } + + public InetSocketAddress getRemoteAddress() { + return channel.getRemoteAddress(); + } + + public ChannelHandler getChannelHandler() { + return channel.getChannelHandler(); + } + + public boolean isConnected() { + return channel.isConnected(); + } + + public InetSocketAddress getLocalAddress() { + return channel.getLocalAddress(); + } + + public boolean hasAttribute(String key) { + return channel.hasAttribute(key); + } + + public void send(Object message) throws RemotingException { + channel.send(message); + } + + public Object getAttribute(String key) { + return channel.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + channel.setAttribute(key, value); + } + + public void send(Object message, boolean sent) throws RemotingException { + channel.send(message, sent); + } + + public void removeAttribute(String key) { + channel.removeAttribute(key); + } + + public void close() { + channel.close(); + } + public void close(int timeout) { + channel.close(timeout); + } + + public boolean isClosed() { + return channel.isClosed(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelHandlerAdapter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelHandlerAdapter.java new file mode 100644 index 0000000000..806921c621 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelHandlerAdapter.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * ChannelHandlerAdapter. + * + * @author qian.lei + */ +public class ChannelHandlerAdapter implements ChannelHandler { + + public void connected(Channel channel) throws RemotingException { + } + + public void disconnected(Channel channel) throws RemotingException { + } + + public void sent(Channel channel, Object message) throws RemotingException { + } + + public void received(Channel channel, Object message) throws RemotingException { + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelHandlerDispatcher.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelHandlerDispatcher.java new file mode 100644 index 0000000000..fd0d89587b --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ChannelHandlerDispatcher.java @@ -0,0 +1,115 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArraySet; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; + +/** + * ChannelListenerDispatcher + * + * @author william.liangf + */ +public class ChannelHandlerDispatcher implements ChannelHandler { + + private static final Logger logger = LoggerFactory.getLogger(ChannelHandlerDispatcher.class); + + private final Collection channelHandlers = new CopyOnWriteArraySet(); + + public ChannelHandlerDispatcher() { + } + + public ChannelHandlerDispatcher(ChannelHandler... handlers) { + this(handlers == null ? null : Arrays.asList(handlers)); + } + + public ChannelHandlerDispatcher(Collection handlers) { + if (handlers != null && handlers.size() > 0) { + this.channelHandlers.addAll(handlers); + } + } + + public Collection getChannelHandlers() { + return channelHandlers; + } + + public ChannelHandlerDispatcher addChannelHandler(ChannelHandler handler) { + this.channelHandlers.add(handler); + return this; + } + + public ChannelHandlerDispatcher removeChannelHandler(ChannelHandler handler) { + this.channelHandlers.remove(handler); + return this; + } + + public void connected(Channel channel) { + for (ChannelHandler listener : channelHandlers) { + try { + listener.connected(channel); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + + public void disconnected(Channel channel) { + for (ChannelHandler listener : channelHandlers) { + try { + listener.disconnected(channel); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + + public void sent(Channel channel, Object message) { + for (ChannelHandler listener : channelHandlers) { + try { + listener.sent(channel, message); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + + public void received(Channel channel, Object message) { + for (ChannelHandler listener : channelHandlers) { + try { + listener.received(channel, message); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + + public void caught(Channel channel, Throwable exception) { + for (ChannelHandler listener : channelHandlers) { + try { + listener.caught(channel, exception); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ClientDelegate.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ClientDelegate.java new file mode 100644 index 0000000000..fcb65ef11b --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ClientDelegate.java @@ -0,0 +1,115 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * ClientDelegate + * + * @author william.liangf + */ +public class ClientDelegate implements Client { + + private transient Client client; + + public ClientDelegate() { + } + + public ClientDelegate(Client client){ + setClient(client); + } + + public Client getClient() { + return client; + } + + public void setClient(Client client) { + if (client == null) { + throw new IllegalArgumentException("client == null"); + } + this.client = client; + } + + public void reset(URL url) { + client.reset(url); + } + + public URL getUrl() { + return client.getUrl(); + } + + public InetSocketAddress getRemoteAddress() { + return client.getRemoteAddress(); + } + + public void reconnect() throws RemotingException { + client.reconnect(); + } + + public ChannelHandler getChannelHandler() { + return client.getChannelHandler(); + } + + public boolean isConnected() { + return client.isConnected(); + } + + public InetSocketAddress getLocalAddress() { + return client.getLocalAddress(); + } + + public boolean hasAttribute(String key) { + return client.hasAttribute(key); + } + + public void send(Object message) throws RemotingException { + client.send(message); + } + + public Object getAttribute(String key) { + return client.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + client.setAttribute(key, value); + } + + public void send(Object message, boolean sent) throws RemotingException { + client.send(message, sent); + } + + public void removeAttribute(String key) { + client.removeAttribute(key); + } + + public void close() { + client.close(); + } + public void close(int timeout) { + client.close(timeout); + } + + public boolean isClosed() { + return client.isClosed(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ServerDelegate.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ServerDelegate.java new file mode 100644 index 0000000000..70f920181a --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/ServerDelegate.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support; + +import java.net.InetSocketAddress; +import java.util.Collection; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; + +/** + * ServerDelegate + * + * @author william.liangf + */ +public class ServerDelegate implements Server { + + private transient Server server; + + public ServerDelegate() { + } + + public ServerDelegate(Server server){ + setServer(server); + } + + public Server getServer() { + return server; + } + + public void setServer(Server server) { + this.server = server; + } + + public boolean isBound() { + return server.isBound(); + } + + public void reset(URL url) { + server.reset(url); + } + + public Collection getChannels() { + return server.getChannels(); + } + + public Channel getChannel(InetSocketAddress remoteAddress) { + return server.getChannel(remoteAddress); + } + + public URL getUrl() { + return server.getUrl(); + } + + public ChannelHandler getChannelHandler() { + return server.getChannelHandler(); + } + + public InetSocketAddress getLocalAddress() { + return server.getLocalAddress(); + } + + public void send(Object message) throws RemotingException { + server.send(message); + } + + public void send(Object message, boolean sent) throws RemotingException { + server.send(message, sent); + } + + public void close() { + server.close(); + } + + public void close(int timeout) { + server.close(timeout); + } + + public boolean isClosed() { + return server.isClosed(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyChannel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyChannel.java new file mode 100644 index 0000000000..435e149073 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyChannel.java @@ -0,0 +1,178 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.grizzly; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.Grizzly; +import org.glassfish.grizzly.GrizzlyFuture; +import org.glassfish.grizzly.attributes.Attribute; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractChannel; + +/** + * GrizzlyChannel + * + * @author william.liangf + */ +final class GrizzlyChannel extends AbstractChannel { + + private static final Logger logger = LoggerFactory.getLogger(GrizzlyChannel.class); + + private static final String CHANNEL_KEY = GrizzlyChannel.class.getName() + ".CHANNEL"; + + private static final Attribute ATTRIBUTE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(CHANNEL_KEY); + + private final Connection connection; + + /** + * @param connection + * @param url + * @param handler + */ + private GrizzlyChannel(Connection connection, URL url, ChannelHandler handler){ + super(url, handler); + if (connection == null) { + throw new IllegalArgumentException("grizzly connection == null"); + } + this.connection = connection; + } + + static GrizzlyChannel getOrAddChannel(Connection connection, URL url, ChannelHandler handler) { + if (connection == null) { + return null; + } + GrizzlyChannel ret = ATTRIBUTE.get(connection); + if (ret == null) { + ret = new GrizzlyChannel(connection, url, handler); + if (connection.isOpen()) { + ATTRIBUTE.set(connection, ret); + } + } + return ret; + } + + static void removeChannelIfDisconnectd(Connection connection) { + if (connection != null && ! connection.isOpen()) { + ATTRIBUTE.remove(connection); + } + } + + public InetSocketAddress getRemoteAddress() { + return (InetSocketAddress) connection.getPeerAddress(); + } + + public boolean isConnected() { + return connection.isOpen(); + } + + public InetSocketAddress getLocalAddress() { + return (InetSocketAddress) connection.getLocalAddress(); + } + + @SuppressWarnings("rawtypes") + public void send(Object message, boolean sent) throws RemotingException { + super.send(message, sent); + + int timeout = 0; + try { + GrizzlyFuture future = connection.write(message); + if (sent) { + timeout = getUrl().getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + future.get(timeout, TimeUnit.MILLISECONDS); + } + } + catch (TimeoutException e) { + throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + + "in timeout(" + timeout + "ms) limit", e); + } + catch (Throwable e) { + throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e); + } + } + + public void close() { + try { + super.close(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + removeChannelIfDisconnectd(connection); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + if (logger.isInfoEnabled()) { + logger.info("Close grizzly channel " + connection); + } + connection.close(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + + public boolean hasAttribute(String key) { + return getAttribute(key) == null; + } + + public Object getAttribute(String key) { + return Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(key).get(connection); + } + + public void setAttribute(String key, Object value) { + Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(key).set(connection, value); + } + + public void removeAttribute(String key) { + Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(key).remove(connection); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((connection == null) ? 0 : connection.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + GrizzlyChannel other = (GrizzlyChannel) obj; + if (connection == null) { + if (other.connection != null) return false; + } else if (!connection.equals(other.connection)) return false; + return true; + } + + @Override + public String toString() { + return "GrizzlyChannel [connection=" + connection + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyClient.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyClient.java new file mode 100644 index 0000000000..3d5c3cf1b2 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyClient.java @@ -0,0 +1,105 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.grizzly; + +import java.util.concurrent.TimeUnit; + +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.filterchain.FilterChainBuilder; +import org.glassfish.grizzly.filterchain.TransportFilter; +import org.glassfish.grizzly.nio.transport.TCPNIOTransport; +import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder; +import org.glassfish.grizzly.strategies.SameThreadIOStrategy; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractClient; + +/** + * GrizzlyClient + * + * @author william.liangf + */ +public class GrizzlyClient extends AbstractClient { + + private TCPNIOTransport transport; + + private volatile Connection connection; // volatile, please copy reference to use + + public GrizzlyClient(URL url, ChannelHandler handler) throws RemotingException { + super(url, handler); + } + + @Override + protected void doOpen() throws Throwable { + FilterChainBuilder filterChainBuilder = FilterChainBuilder.stateless(); + filterChainBuilder.add(new TransportFilter()); + filterChainBuilder.add(new GrizzlyCodecAdapter(getCodec(), getUrl(), this)); + filterChainBuilder.add(new GrizzlyHandler(getUrl(), this)); + TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance(); + ThreadPoolConfig config = builder.getWorkerThreadPoolConfig(); + config.setPoolName(CLIENT_THREAD_POOL_NAME) + .setQueueLimit(-1) + .setCorePoolSize(0) + .setMaxPoolSize(Integer.MAX_VALUE) + .setKeepAliveTime(60L, TimeUnit.SECONDS); + builder.setTcpNoDelay(true).setKeepAlive(true) + .setConnectionTimeout(getTimeout()) + .setIOStrategy(SameThreadIOStrategy.getInstance()); + transport = builder.build(); + transport.setProcessor(filterChainBuilder.build()); + transport.start(); + } + + + + @Override + protected void doConnect() throws Throwable { + connection = transport.connect(getConnectAddress()) + .get(getUrl().getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT), TimeUnit.MILLISECONDS); + } + + @Override + protected void doDisConnect() throws Throwable { + try { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } catch (Throwable t) { + logger.warn(t.getMessage()); + } + } + + @Override + protected void doClose() throws Throwable { + try { + transport.stop(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + @Override + protected Channel getChannel() { + Connection c = connection; + if (c == null || ! c.isOpen()) + return null; + return GrizzlyChannel.getOrAddChannel(c, getUrl(), this); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyCodecAdapter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyCodecAdapter.java new file mode 100644 index 0000000000..46ed9f0289 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyCodecAdapter.java @@ -0,0 +1,189 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.grizzly; + +import java.io.IOException; + +import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.filterchain.BaseFilter; +import org.glassfish.grizzly.filterchain.FilterChainContext; +import org.glassfish.grizzly.filterchain.NextAction; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.exchange.Response; + +/** + * GrizzlyCodecAdapter + * + * @author william.liangf + */ +public class GrizzlyCodecAdapter extends BaseFilter { + + private static final String BUFFER_KEY = GrizzlyCodecAdapter.class.getName() + ".BUFFER"; + + private final Codec upstreamCodec; + private final Codec downstreamCodec; + + private final URL url; + + private final ChannelHandler handler; + + private final int bufferSize; + + public GrizzlyCodecAdapter(Codec codec, URL url, ChannelHandler handler){ + this(codec, codec, url, handler); + } + /** + * server 端如果有消息发送需要分开codec,默认的上行code是dubbo1兼容的 + */ + public GrizzlyCodecAdapter(Codec upstreamCodec, Codec downstreamCodec, URL url, ChannelHandler handler){ + this.upstreamCodec = upstreamCodec; + this.downstreamCodec = downstreamCodec; + this.url = url; + this.handler = handler; + int b = url.getPositiveIntParameter(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE); + this.bufferSize = b >= Constants.MIN_BUFFER_SIZE && b <= Constants.MAX_BUFFER_SIZE ? b : Constants.DEFAULT_BUFFER_SIZE; + } + + @Override + public NextAction handleWrite(FilterChainContext context) throws IOException { + Connection connection = context.getConnection(); + GrizzlyChannel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + UnsafeByteArrayOutputStream output = new UnsafeByteArrayOutputStream(1024); // 不需要关闭 + + if(!(context.getMessage() instanceof Response)){ + downstreamCodec.encode(channel, output, context.getMessage()); + }else{ + upstreamCodec.encode(channel, output, context.getMessage()); + } + + GrizzlyChannel.removeChannelIfDisconnectd(connection); + byte[] bytes = output.toByteArray(); + Buffer buffer = connection.getTransport().getMemoryManager().allocate(bytes.length); + buffer.put(bytes); + buffer.flip(); + buffer.allowBufferDispose(true); + context.setMessage(buffer); + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + return context.getInvokeAction(); + } + + @Override + public NextAction handleRead(FilterChainContext context) throws IOException { + Object message = context.getMessage(); + Connection connection = context.getConnection(); + Channel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + if (message instanceof Buffer) { // 收到新的数据包 + Buffer buffer = (Buffer) message; // 缓存 + int readable = buffer.capacity(); // 本次可读取新数据的大小 + if (readable == 0) { + return context.getStopAction(); + } + byte[] bytes; // byte[]缓存区,将Buffer转成byte[],再转成UnsafeByteArrayInputStream + int offset; // 指向已用数据的偏移量,off之前的数据都是已用过的 + int limit; // 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的有效数据 + Object[] remainder = (Object[]) channel.getAttribute(BUFFER_KEY); // 上次序列化剩下的数据 + channel.removeAttribute(BUFFER_KEY); + if (remainder == null) { // 如果没有,创建新的bytes缓存 + bytes = new byte[bufferSize]; + offset = 0; + limit = 0; + } else { // 如果有,使用剩下的bytes缓存 + bytes = (byte[]) remainder[0]; + offset = (Integer) remainder[1]; + limit = (Integer) remainder[2]; + } + return receive(context, channel, buffer, readable, bytes, offset, limit); + } else if (message instanceof Object[]) { // 同一Buffer多轮Filter,即:一个Buffer里有多个请求 + Object[] remainder = (Object[]) message; + Buffer buffer = (Buffer) remainder[0]; + int readable = (Integer) remainder[1]; + byte[] bytes = (byte[]) remainder[2]; + int offset = (Integer) remainder[3]; + int limit = (Integer) remainder[4]; + return receive(context, channel, buffer, readable, bytes, offset, limit); + } else { // 其它事件直接往下传 + return context.getInvokeAction(); + } + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + } + + /* + * 接收 + * + * @param context 上下文 + * @param channel 通道 + * @param buffer 缓存 + * @param readable 缓存可读 + * @param bytes 输入缓存 + * @param offset 指向已读数据的偏移量,off之前的数据都是已用过的 + * @param limit 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的数据 + * @return 后续动作 + * @throws IOException + */ + private NextAction receive(FilterChainContext context, Channel channel, Buffer buffer, int readable, byte[] bytes, int offset, int limit) throws IOException { + for(;;) { + int read = Math.min(readable, bytes.length - limit); // 取bytes缓存空闲区,和可读取新数据,的最小值,即:此次最多读写数据的大小 + buffer.get(bytes, limit, read); // 从可读取新数据中,读取数据,尽量填满bytes缓存空闲区 + limit += read; // 有效数据变长 + readable -= read; // 可读数据变少 + UnsafeByteArrayInputStream input = new UnsafeByteArrayInputStream(bytes, offset, limit - offset); // 将bytes缓存转成InputStream,不需要关闭 + Object msg = upstreamCodec.decode(channel, input); // 调用Codec接口,解码数据 + if (msg == Codec.NEED_MORE_INPUT) { // 如果Codec觉得数据不够,不足以解码成一个对象 + if (readable == 0) { // 如果没有更多可读数据 + channel.setAttribute(BUFFER_KEY, new Object[] { bytes, offset, limit }); // 放入通道属性中,等待下一个Buffer的到来 + return context.getStopAction(); + } else { // 扩充或挪出空闲区,并循环,直到可读数据都加载到bytes缓存 + if (offset == 0) { // 如果bytes缓存全部没有被使用,如果这时数据还不够 + bytes = Bytes.copyOf(bytes, bytes.length << 1); // 将bytes缓存扩大一倍 + } else { // 如果bytes缓存有一段数据已被使用 + int len = limit - offset; // 计算有效数据长度 + System.arraycopy(bytes, offset, bytes, 0, len); // 将数据向前移到,压缩到已使用的部分,这样limit后面就会多出一些空闲,可以放数据 + offset = 0; // 移到后,bytes缓存没有数据被使用 + limit = len; // 移到后,有效数据都在bytes缓存最前面 + } + } + } else { // 如果解析出一个结果 + int position = input.position(); // 记录InputStream用了多少 + if (position == offset) { // 如果InputStream没有被读过,就返回了数据,直接报错,否则InputStream永远读不完,会死递归 + throw new IOException("Decode without read data."); + } + offset = position; // 记录已读数据 + context.setMessage(msg); // 将消息改为解码后的对象,以便被后面的Filter使用。 + if (limit - offset > 0 || readable > 0) { // 如果有效数据没有被读完,或者Buffer区还有未读数据 + return context.getInvokeAction(new Object[] { buffer, readable, bytes, offset, limit }); // 正常执行完Filter,并重新发起一轮Filter,继续读 + } else { // 否则所有数据读完 + return context.getInvokeAction(); // 正常执行完Filter + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyHandler.java new file mode 100644 index 0000000000..96601e063c --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyHandler.java @@ -0,0 +1,119 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.grizzly; + +import java.io.IOException; + +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.filterchain.BaseFilter; +import org.glassfish.grizzly.filterchain.FilterChainContext; +import org.glassfish.grizzly.filterchain.NextAction; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * GrizzlyHandler + * + * @author william.liangf + */ +public class GrizzlyHandler extends BaseFilter { + + private static final Logger logger = LoggerFactory.getLogger(GrizzlyHandler.class); + + private final URL url; + + private final ChannelHandler handler; + + public GrizzlyHandler(URL url, ChannelHandler handler){ + this.url = url; + this.handler = handler; + } + + @Override + public NextAction handleConnect(FilterChainContext ctx) throws IOException { + Connection connection = ctx.getConnection(); + GrizzlyChannel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + handler.connected(channel); + } catch (RemotingException e) { + throw new IOException(StringUtils.toString(e)); + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + return ctx.getInvokeAction(); + } + + @Override + public NextAction handleClose(FilterChainContext ctx) throws IOException { + Connection connection = ctx.getConnection(); + GrizzlyChannel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + handler.disconnected(channel); + } catch (RemotingException e) { + throw new IOException(StringUtils.toString(e)); + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + return ctx.getInvokeAction(); + } + + @Override + public NextAction handleRead(FilterChainContext ctx) throws IOException { + Connection connection = ctx.getConnection(); + GrizzlyChannel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + handler.received(channel, ctx.getMessage()); + } catch (RemotingException e) { + throw new IOException(StringUtils.toString(e)); + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + return ctx.getInvokeAction(); + } + + @Override + public NextAction handleWrite(FilterChainContext ctx) throws IOException { + Connection connection = ctx.getConnection(); + GrizzlyChannel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + handler.sent(channel, ctx.getMessage()); + } catch (RemotingException e) { + throw new IOException(StringUtils.toString(e)); + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + return ctx.getInvokeAction(); + } + + @Override + public void exceptionOccurred(FilterChainContext ctx, Throwable error) { + Connection connection = ctx.getConnection(); + GrizzlyChannel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); + try { + handler.caught(channel, error); + } catch (RemotingException e) { + logger.error("RemotingException on channel " + channel, e); + } finally { + GrizzlyChannel.removeChannelIfDisconnectd(connection); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyServer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyServer.java new file mode 100644 index 0000000000..f85ece2179 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyServer.java @@ -0,0 +1,118 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.grizzly; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import org.glassfish.grizzly.filterchain.FilterChainBuilder; +import org.glassfish.grizzly.filterchain.TransportFilter; +import org.glassfish.grizzly.nio.transport.TCPNIOTransport; +import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder; +import org.glassfish.grizzly.strategies.SameThreadIOStrategy; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractServer; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelHandlers; + +/** + * GrizzlyServer + * + * @author william.liangf + */ +public class GrizzlyServer extends AbstractServer { + + private final Map channels = new ConcurrentHashMap(); // + + private TCPNIOTransport transport; + + public GrizzlyServer(URL url, ChannelHandler handler) throws RemotingException { + super(url, ChannelHandlers.wrap(handler, url)); + } + + @Override + protected void doOpen() throws Throwable { + FilterChainBuilder filterChainBuilder = FilterChainBuilder.stateless(); + filterChainBuilder.add(new TransportFilter()); + + filterChainBuilder.add(new GrizzlyCodecAdapter(getCodec(), getDownstreamCodec(), getUrl(), this)); + filterChainBuilder.add(new GrizzlyHandler(getUrl(), this)); + TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance(); + ThreadPoolConfig config = builder.getWorkerThreadPoolConfig(); + config.setPoolName(SERVER_THREAD_POOL_NAME).setQueueLimit(-1); + String threadpool = getUrl().getParameter(Constants.THREADPOOL_KEY, Constants.DEFAULT_THREADPOOL); + if (Constants.DEFAULT_THREADPOOL.equals(threadpool)) { + int threads = getUrl().getPositiveIntParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); + config.setCorePoolSize(threads).setMaxPoolSize(threads) + .setKeepAliveTime(0L, TimeUnit.SECONDS); + } else if ("cached".equals(threadpool)) { + int threads = getUrl().getPositiveIntParameter(Constants.THREADS_KEY, Integer.MAX_VALUE); + config.setCorePoolSize(0).setMaxPoolSize(threads) + .setKeepAliveTime(60L, TimeUnit.SECONDS); + } else { + throw new IllegalArgumentException("Unsupported threadpool type " + threadpool); + } + builder.setKeepAlive(true).setReuseAddress(false) + .setIOStrategy(SameThreadIOStrategy.getInstance()); + transport = builder.build(); + transport.setProcessor(filterChainBuilder.build()); + transport.bind(getBindAddress()); + transport.start(); + } + + @Override + protected void doClose() throws Throwable { + try { + transport.stop(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + public boolean isBound() { + return ! transport.isStopped(); + } + + public Collection getChannels() { + return channels.values(); + } + + public Channel getChannel(InetSocketAddress remoteAddress) { + return channels.get(NetUtils.toAddressString(remoteAddress)); + } + + @Override + public void connected(Channel ch) throws RemotingException { + channels.put(NetUtils.toAddressString(ch.getRemoteAddress()), ch); + super.connected(ch); + } + + @Override + public void disconnected(Channel ch) throws RemotingException { + channels.remove(NetUtils.toAddressString(ch.getRemoteAddress())); + super.disconnected(ch); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyTransporter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyTransporter.java new file mode 100644 index 0000000000..0c400f20c6 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/grizzly/GrizzlyTransporter.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.grizzly; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.Transporter; + +/** + * GrizzlyTransporter + * + * @author william.liangf + */ +@Extension(GrizzlyTransporter.NAME) +public class GrizzlyTransporter implements Transporter { + + public static final String NAME = "grizzly"; + + public Server bind(URL url, ChannelHandler listener) throws RemotingException { + return new GrizzlyServer(url, listener); + } + + public Client connect(URL url, ChannelHandler listener) throws RemotingException { + return new GrizzlyClient(url, listener); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ChannelEventRunnable.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ChannelEventRunnable.java new file mode 100644 index 0000000000..60d5f353c1 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ChannelEventRunnable.java @@ -0,0 +1,98 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; + +/** + * @author chao.liuc + * + */ +public class ChannelEventRunnable implements Runnable { + private final ChannelHandler handler; + private final Channel channel; + private final ChannelState state; + private final Throwable exception; + private final Object message; + + public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state) { + this(channel, handler, state, null); + } + + public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message) { + this(channel, handler, state, message, null); + } + + public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Throwable t) { + this(channel, handler, state, null , t); + } + + public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message, Throwable exception) { + this.channel = channel; + this.handler = handler; + this.state = state; + this.message = message; + this.exception = exception; + } + + public void run() { + switch (state) { + case CONNECTED: + try{ + handler.connected(channel); + }catch (Exception e) { + throw new RuntimeException("ChannelEventRunnable handle error,channel is "+channel,e); + } + break; + case DISCONNECTED: + try{ + handler.disconnected(channel); + }catch (Exception e) { + throw new RuntimeException("ChannelEventRunnable handle error,channel is "+channel,e); + } + break; + case SENT: + try{ + handler.sent(channel,message); + }catch (Exception e) { + throw new RuntimeException("ChannelEventRunnable handle error,channel is "+channel+",message is "+ message,e); + } + + break; + case RECEIVED: + try{ + handler.received(channel, message); + }catch (Exception e) { + throw new RuntimeException("ChannelEventRunnable handle error,channel is "+channel+",message is "+ message,e); + } + break; + case CAUGHT: + try{ + handler.caught(channel, exception); + }catch (Exception e) { + throw new RuntimeException("ChannelEventRunnable handle error,channel is "+channel +", message is: "+message+" exception is "+exception,e); + } + + break; + } + } + + public enum ChannelState{ + CONNECTED,DISCONNECTED,SENT,RECEIVED,CAUGHT + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ChannelHandlers.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ChannelHandlers.java new file mode 100644 index 0000000000..2da4aac60d --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ChannelHandlers.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ChannelHandlerWrapper; + +/** + * @author chao.liuc + * + */ +public class ChannelHandlers { + + public static ChannelHandler wrap(ChannelHandler handler, URL url){ + return ExtensionLoader.getExtensionLoader(ChannelHandlerWrapper.class) + .getAdaptiveExtension().wrap(handler, url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ConnectionOrderedChannelHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ConnectionOrderedChannelHandler.java new file mode 100644 index 0000000000..ecf2879b9c --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ConnectionOrderedChannelHandler.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.threadpool.support.AbortPolicyWithReport; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ExecutionException; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelEventRunnable.ChannelState; + +public class ConnectionOrderedChannelHandler extends WrappedChannelHandler { + + protected final ThreadPoolExecutor connectionExecutor; + private final int queuewarninglimit ; + + public ConnectionOrderedChannelHandler(ChannelHandler handler, URL url) { + super(handler, url); + String threadName = url.getParameter(Constants.THREAD_NAME_KEY,Constants.DEFAULT_THREAD_NAME); + connectionExecutor = new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(url.getPositiveIntParameter(Constants.CONNECT_QUENE_CAPACITY, Integer.MAX_VALUE)), + new NamedThreadFactory(threadName, true), + new AbortPolicyWithReport(threadName, url) + ); // FIXME 没有地方释放connectionExecutor! + queuewarninglimit = url.getIntParameter(Constants.CONNECT_QUENE_WARNING_SIZE, Constants.DEFAULT_CONNECT_QUENE_WARNING_SIZE); + } + + public void connected(Channel channel) throws RemotingException { + try{ + checkQueueLength(); + connectionExecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.CONNECTED)); + }catch (Throwable t) { + throw new ExecutionException("connect event", channel, getClass()+" error when process connected event ." , t); + } + } + + public void disconnected(Channel channel) throws RemotingException { + try{ + checkQueueLength(); + connectionExecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.DISCONNECTED)); + }catch (Throwable t) { + throw new ExecutionException("disconnected event", channel, getClass()+" error when process disconnected event ." , t); + } + } + + public void received(Channel channel, Object message) throws RemotingException { + ExecutorService cexecutor = executor; + if (cexecutor == null || cexecutor.isShutdown()) { + cexecutor = SHARED_EXECUTOR; + } + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.RECEIVED, message)); + }catch (Throwable t) { + throw new ExecutionException(message, channel, getClass()+" error when process received event ." , t); + } + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + ExecutorService cexecutor = executor; + if (cexecutor == null || cexecutor.isShutdown()) { + cexecutor = SHARED_EXECUTOR; + } + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.CAUGHT, exception)); + }catch (Throwable t) { + throw new ExecutionException("caught event", channel, getClass()+" error when process caught event ." , t); + } + } + + private void checkQueueLength(){ + if (connectionExecutor.getQueue().size() > queuewarninglimit){ + logger.warn(new IllegalThreadStateException("connectionordered channel handler `quene size: "+connectionExecutor.getQueue().size()+" exceed the warning limit number :"+queuewarninglimit)); + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ConnectionOrderedChannelHandlerWrapper.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ConnectionOrderedChannelHandlerWrapper.java new file mode 100644 index 0000000000..cd85030189 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ConnectionOrderedChannelHandlerWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ChannelHandlerWrapper; + +/** + * connect disconnect 保证顺序. + * + * @author chao.liuc + */ +@Extension(ConnectionOrderedChannelHandlerWrapper.NAME) +public class ConnectionOrderedChannelHandlerWrapper implements ChannelHandlerWrapper { + + public static final String NAME = "connection"; + + public ChannelHandler wrap(ChannelHandler handler, URL url) { + return new ConnectionOrderedChannelHandler(handler, url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DefaultChannelHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DefaultChannelHandler.java new file mode 100644 index 0000000000..87f19ddd91 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DefaultChannelHandler.java @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import java.util.concurrent.ExecutorService; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ExecutionException; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelEventRunnable.ChannelState; + +public class DefaultChannelHandler extends WrappedChannelHandler { + + public DefaultChannelHandler(ChannelHandler handler, URL url) { + super(handler, url); + } + + public void connected(Channel channel) throws RemotingException { + ExecutorService cexecutor = getExecutorService(); + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.CONNECTED)); + }catch (Throwable t) { + throw new ExecutionException("connect event", channel, getClass()+" error when process connected event ." , t); + } + } + + public void disconnected(Channel channel) throws RemotingException { + ExecutorService cexecutor = getExecutorService(); + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.DISCONNECTED)); + }catch (Throwable t) { + throw new ExecutionException("disconnect event", channel, getClass()+" error when process disconnected event ." , t); + } + } + + public void received(Channel channel, Object message) throws RemotingException { + ExecutorService cexecutor = getExecutorService(); + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.RECEIVED, message)); + }catch (Throwable t) { + throw new ExecutionException(message, channel, getClass()+" error when process received event ." , t); + } + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + ExecutorService cexecutor = getExecutorService(); + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.CAUGHT, exception)); + }catch (Throwable t) { + throw new ExecutionException("caught event", channel, getClass()+" error when process caught event ." , t); + } + } + + private ExecutorService getExecutorService() { + ExecutorService cexecutor = executor; + if (cexecutor == null || cexecutor.isShutdown()) { + cexecutor = SHARED_EXECUTOR; + } + return cexecutor; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DefaultChannelHandlerWrapper.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DefaultChannelHandlerWrapper.java new file mode 100644 index 0000000000..870379fb4f --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DefaultChannelHandlerWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ChannelHandlerWrapper; + +/** + * 默认的线程池配置 + * + * @author chao.liuc + */ +@Extension(DefaultChannelHandlerWrapper.NAME) +public class DefaultChannelHandlerWrapper implements ChannelHandlerWrapper { + + public static final String NAME = "default"; + + public ChannelHandler wrap(ChannelHandler handler, URL url) { + return new DefaultChannelHandler(handler, url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DirectChannelHandlerWrapper.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DirectChannelHandlerWrapper.java new file mode 100644 index 0000000000..2b01d1719d --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/DirectChannelHandlerWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ChannelHandlerWrapper; + +/** + * 不派发线程池。 + * + * @author chao.liuc + */ +@Extension(DirectChannelHandlerWrapper.NAME) +public class DirectChannelHandlerWrapper implements ChannelHandlerWrapper { + + public static final String NAME = "direct"; + + public ChannelHandler wrap(ChannelHandler handler, URL url) { + return handler; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ExecutionChannelHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ExecutionChannelHandler.java new file mode 100644 index 0000000000..425c91d249 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ExecutionChannelHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelEventRunnable.ChannelState; + +public class ExecutionChannelHandler extends WrappedChannelHandler { + + public ExecutionChannelHandler(ChannelHandler handler, URL url) { + super(handler, url); + } + + public void connected(Channel channel) throws RemotingException { + executor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.CONNECTED)); + } + + public void disconnected(Channel channel) throws RemotingException { + executor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.DISCONNECTED)); + } + + public void received(Channel channel, Object message) throws RemotingException { + executor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.RECEIVED, message)); + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + executor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.CAUGHT, exception)); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ExecutionChannelHandlerWrapper.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ExecutionChannelHandlerWrapper.java new file mode 100644 index 0000000000..b68c36bf1b --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/ExecutionChannelHandlerWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ChannelHandlerWrapper; + +/** + * 除发送全部使用线程池处理 + * + * @author chao.liuc + */ +@Extension(ExecutionChannelHandlerWrapper.NAME) +public class ExecutionChannelHandlerWrapper implements ChannelHandlerWrapper { + + public static final String NAME = "execution"; + + public ChannelHandler wrap(ChannelHandler handler, URL url) { + return new ExecutionChannelHandler(handler, url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/MessageOnlyChannelHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/MessageOnlyChannelHandler.java new file mode 100644 index 0000000000..2a6de6f5d7 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/MessageOnlyChannelHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import java.util.concurrent.ExecutorService; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ExecutionException; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelEventRunnable.ChannelState; + +public class MessageOnlyChannelHandler extends WrappedChannelHandler { + + public MessageOnlyChannelHandler(ChannelHandler handler, URL url) { + super(handler, url); + } + + public void received(Channel channel, Object message) throws RemotingException { + ExecutorService cexecutor = executor; + if (cexecutor == null || cexecutor.isShutdown()) { + cexecutor = SHARED_EXECUTOR; + } + try{ + cexecutor.execute(new ChannelEventRunnable(channel, handler ,ChannelState.RECEIVED, message)); + }catch (Throwable t) { + throw new ExecutionException(message, channel, getClass()+" error when process received event ." , t); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/MessageOnlyChannelHandlerWrapper.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/MessageOnlyChannelHandlerWrapper.java new file mode 100644 index 0000000000..efe2374dd2 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/MessageOnlyChannelHandlerWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.ChannelHandlerWrapper; + +/** + * 只有message receive使用线程池. + * + * @author chao.liuc + */ +@Extension(MessageOnlyChannelHandlerWrapper.NAME) +public class MessageOnlyChannelHandlerWrapper implements ChannelHandlerWrapper { + + public static final String NAME = "message"; + + public ChannelHandler wrap(ChannelHandler handler, URL url) { + return new MessageOnlyChannelHandler(handler, url); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/WrappedChannelHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/WrappedChannelHandler.java new file mode 100644 index 0000000000..d5a6fd1176 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/handler/WrappedChannelHandler.java @@ -0,0 +1,90 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.handler; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.threadpool.ThreadPool; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +public class WrappedChannelHandler implements ChannelHandler { + + protected static final Logger logger = LoggerFactory.getLogger(WrappedChannelHandler.class); + + protected static final ExecutorService SHARED_EXECUTOR = Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true)); + + protected final ExecutorService executor; + + protected final ChannelHandler handler; + + protected final URL url; + + public WrappedChannelHandler(ChannelHandler handler, URL url) { + this.handler = handler; + this.url = url; + executor = (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url); + } + + public void close() { + try { + if (executor instanceof ExecutorService) { + ((ExecutorService)executor).shutdown(); + } + } catch (Throwable t) { + logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t); + } + } + + public void connected(Channel channel) throws RemotingException { + handler.connected(channel); + } + + public void disconnected(Channel channel) throws RemotingException { + handler.disconnected(channel); + } + + public void sent(Channel channel, Object message) throws RemotingException { + handler.sent(channel, message); + } + + public void received(Channel channel, Object message) throws RemotingException { + handler.received(channel, message); + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + handler.caught(channel, exception); + } + + public ExecutorService getExecutor() { + return executor; + } + + public ChannelHandler getHandler() { + return handler; + } + + public URL getUrl() { + return url; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaChannel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaChannel.java new file mode 100644 index 0000000000..9d9a90df01 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaChannel.java @@ -0,0 +1,172 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.mina; + +import java.net.InetSocketAddress; + +import org.apache.mina.common.IoSession; +import org.apache.mina.common.WriteFuture; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractChannel; + +/** + * MinaChannel + * + * @author qian.lei + * @author william.liangf + */ +final class MinaChannel extends AbstractChannel { + + private static final Logger logger = LoggerFactory.getLogger(MinaChannel.class); + + private static final String CHANNEL_KEY = MinaChannel.class.getName() + ".CHANNEL"; + + private final IoSession session; + + private MinaChannel(IoSession session, URL url, ChannelHandler handler){ + super(url, handler); + if (session == null) { + throw new IllegalArgumentException("mina session == null"); + } + this.session = session; + } + + static MinaChannel getOrAddChannel(IoSession session, URL url, ChannelHandler handler) { + if (session == null) { + return null; + } + MinaChannel ret = (MinaChannel) session.getAttribute(CHANNEL_KEY); + if (ret == null) { + ret = new MinaChannel(session, url, handler); + if (session.isConnected()) { + MinaChannel old = (MinaChannel) session.setAttribute(CHANNEL_KEY, ret); + if (old != null) { + session.setAttribute(CHANNEL_KEY, old); + ret = old; + } + } + } + return ret; + } + + static void removeChannelIfDisconnectd(IoSession session) { + if (session != null && ! session.isConnected()) { + session.removeAttribute(CHANNEL_KEY); + } + } + + public InetSocketAddress getLocalAddress() { + return (InetSocketAddress) session.getLocalAddress(); + } + + public InetSocketAddress getRemoteAddress() { + return (InetSocketAddress) session.getRemoteAddress(); + } + + public boolean isConnected() { + return session.isConnected(); + } + + public void send(Object message, boolean sent) throws RemotingException { + super.send(message, sent); + + boolean success = true; + int timeout = 0; + try { + WriteFuture future = session.write(message); + if (sent) { + timeout = getUrl().getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + success = future.join(timeout); + } + } catch (Throwable e) { + throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e); + } + + if(!success) { + throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + + "in timeout(" + timeout + "ms) limit"); + } + } + + public void close() { + try { + super.close(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + removeChannelIfDisconnectd(session); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + if (logger.isInfoEnabled()) { + logger.info("CLose mina channel " + session); + } + session.close(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + + public boolean hasAttribute(String key) { + return session.containsAttribute(key); + } + + public Object getAttribute(String key) { + return session.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + session.setAttribute(key, value); + } + + public void removeAttribute(String key) { + session.removeAttribute(key); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((session == null) ? 0 : session.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + MinaChannel other = (MinaChannel) obj; + if (session == null) { + if (other.session != null) return false; + } else if (!session.equals(other.session)) return false; + return true; + } + + @Override + public String toString() { + return "MinaChannel [session=" + session + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaClient.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaClient.java new file mode 100644 index 0000000000..4d98571af4 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaClient.java @@ -0,0 +1,177 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.mina; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.mina.common.ConnectFuture; +import org.apache.mina.common.IoFuture; +import org.apache.mina.common.IoFutureListener; +import org.apache.mina.common.IoSession; +import org.apache.mina.common.ThreadModel; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.mina.transport.socket.nio.SocketConnector; +import org.apache.mina.transport.socket.nio.SocketConnectorConfig; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractClient; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelHandlers; + +/** + * Mina client. + * + * @author qian.lei + * @author william.liangf + */ +public class MinaClient extends AbstractClient { + + private static final Map connectors = new ConcurrentHashMap(); + + private String connectorKey; + + private SocketConnector connector; + + private volatile IoSession session; // volatile, please copy reference to use + + public MinaClient(final URL url, final ChannelHandler handler) throws RemotingException { + super(url, wrapChannelHandler(url, handler)); + } + + protected static ChannelHandler wrapChannelHandler(URL url, ChannelHandler handler){ + url = url.addParameter(Constants.THREAD_NAME_KEY, CLIENT_THREAD_POOL_NAME) + .addParameter(Constants.THREADPOOL_KEY, Constants.DEFAULT_CLIENT_THREADPOOL); + return ChannelHandlers.wrap(handler, url); + } + + @Override + protected void doOpen() throws Throwable { + connectorKey = getUrl().toFullString(); + SocketConnector c = connectors.get(connectorKey); + if (c != null) { + connector = c; + } else { + // set thread pool. + connector = new SocketConnector(Constants.DEFAULT_IO_THREADS, + Executors.newCachedThreadPool(new NamedThreadFactory("MinaClientWorker", true))); + // config + SocketConnectorConfig cfg = (SocketConnectorConfig) connector.getDefaultConfig(); + cfg.setThreadModel(ThreadModel.MANUAL); + cfg.getSessionConfig().setTcpNoDelay(true); + cfg.getSessionConfig().setKeepAlive(true); + int timeout = getTimeout(); + cfg.setConnectTimeout(timeout < 1000 ? 1 : timeout / 1000); + // set codec. + connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MinaCodecAdapter(getCodec(), getUrl(), this))); + connectors.put(connectorKey, connector); + } + } + + @Override + protected void doConnect() throws Throwable { + ConnectFuture future = connector.connect(getConnectAddress(), new MinaHandler(getUrl(), this)); + long start = System.currentTimeMillis(); + final AtomicReference exception = new AtomicReference(); + final CountDownLatch finish = new CountDownLatch(1); // resolve future.awaitUninterruptibly() dead lock + future.addListener(new IoFutureListener() { + public void operationComplete(IoFuture future) { + try { + if (future.isReady()) { + IoSession newSession = future.getSession(); + try { + // 关闭旧的连接 + IoSession oldSession = MinaClient.this.session; // copy reference + if (oldSession != null) { + try { + if (logger.isInfoEnabled()) { + logger.info("Close old mina channel " + oldSession + " on create new mina channel " + newSession); + } + oldSession.close(); + } finally { + MinaChannel.removeChannelIfDisconnectd(oldSession); + } + } + } finally { + if (MinaClient.this.isClosed()) { + try { + if (logger.isInfoEnabled()) { + logger.info("Close new mina channel " + newSession + ", because the client closed."); + } + newSession.close(); + } finally { + MinaClient.this.session = null; + MinaChannel.removeChannelIfDisconnectd(newSession); + } + } else { + MinaClient.this.session = newSession; + } + } + } + } catch (Exception e) { + exception.set(e); + } finally { + finish.countDown(); + } + } + }); + try { + finish.await(getTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RemotingException(this, "Failed to connect to server " + getRemoteAddress() + " client-side timeout " + + getTimeout() + "ms (elapsed: " + (System.currentTimeMillis() - start) + + "ms) from netty client " + NetUtils.getLocalHost() + " using dubbo version " + + Version.getVersion() + ", cause: " + e.getMessage(), e); + } + Throwable e = exception.get(); + if (e != null) { + throw e; + } + } + + @Override + protected void doDisConnect() throws Throwable { + try { + MinaChannel.removeChannelIfDisconnectd(session); + } catch (Throwable t) { + logger.warn(t.getMessage()); + } + } + + @Override + protected void doClose() throws Throwable { + //release mina resouces. + } + + @Override + protected Channel getChannel() { + IoSession s = session; + if (s == null || ! s.isConnected()) + return null; + return MinaChannel.getOrAddChannel(s, getUrl(), this); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaCodecAdapter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaCodecAdapter.java new file mode 100644 index 0000000000..f669738404 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaCodecAdapter.java @@ -0,0 +1,193 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.mina; + +import java.io.IOException; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.IoSession; +import org.apache.mina.filter.codec.ProtocolCodecFactory; +import org.apache.mina.filter.codec.ProtocolDecoder; +import org.apache.mina.filter.codec.ProtocolDecoderOutput; +import org.apache.mina.filter.codec.ProtocolEncoder; +import org.apache.mina.filter.codec.ProtocolEncoderOutput; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.exchange.Response; + +/** + * MinaCodecAdapter. + * + * @author qian.lei + */ +final class MinaCodecAdapter implements ProtocolCodecFactory { + + private static final String BUFFER_KEY = MinaCodecAdapter.class.getName() + ".BUFFER"; + + private final ProtocolEncoder encoder = new InternalEncoder(); + + private final ProtocolDecoder decoder = new InternalDecoder(); + + private final Codec upstreamCodec; + private final Codec downstreamCodec; + + private final URL url; + + private final ChannelHandler handler; + + private final int bufferSize; + + public MinaCodecAdapter(Codec codec, URL url, ChannelHandler handler){ + this(codec,codec,url,handler); + } + + /** + * server 端如果有消息发送需要分开codec,默认的上行code是dubbo1兼容的 + */ + public MinaCodecAdapter(Codec upstreamCodec, Codec downstreamCodec, URL url, ChannelHandler handler){ + this.upstreamCodec = upstreamCodec; + this.downstreamCodec = downstreamCodec; + this.url = url; + this.handler = handler; + int b = url.getPositiveIntParameter(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE); + this.bufferSize = b >= Constants.MIN_BUFFER_SIZE && b <= Constants.MAX_BUFFER_SIZE ? b : Constants.DEFAULT_BUFFER_SIZE; + } + + public ProtocolEncoder getEncoder() { + return encoder; + } + + public ProtocolDecoder getDecoder() { + return decoder; + } + + private class InternalEncoder implements ProtocolEncoder { + + public void dispose(IoSession session) throws Exception { + } + + public void encode(IoSession session, Object msg, ProtocolEncoderOutput out) throws Exception { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(1024); // 不需要关闭 + MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler); + try { + if(!(msg instanceof Response)){ + downstreamCodec.encode(channel, os, msg); + }else{ + upstreamCodec.encode(channel, os, msg); + } + + } finally { + MinaChannel.removeChannelIfDisconnectd(session); + } + out.write(ByteBuffer.wrap(os.toByteArray())); + out.flush(); + } + } + + private class InternalDecoder implements ProtocolDecoder { + + public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception { + int readable = in.limit(); + if (readable <= 0) return; + + int off, limit; + byte[] buf; + // load buffer from context. + Object[] tmp = (Object[]) session.getAttribute(BUFFER_KEY); + if (tmp == null) { + buf = new byte[bufferSize]; + off = limit = 0; + } else { + buf = (byte[]) tmp[0]; + off = (Integer) tmp[1]; + limit = (Integer) tmp[2]; + } + + Channel channel = MinaChannel.getOrAddChannel(session, url, handler); + boolean remaining = true; + Object msg; + UnsafeByteArrayInputStream bis; + try { + do { + // read data into buffer. + int read = Math.min(readable, buf.length - limit); + in.get(buf, limit, read); + limit += read; + readable -= read; + bis = new UnsafeByteArrayInputStream(buf, off, limit - off); // 不需要关闭 + // decode object. + do { + try { + msg = upstreamCodec.decode(channel, bis); + } catch (IOException e) { + remaining = false; + throw e; + } + if (msg == Codec.NEED_MORE_INPUT) { + if (off == 0) { + if (readable > 0) { + buf = Bytes.copyOf(buf, buf.length << 1); + } + } else { + int len = limit - off; + System.arraycopy(buf, off, buf, 0, len); + off = 0; + limit = len; + } + break; + } else { + int pos = bis.position(); + if (pos == off) { + remaining = false; + throw new IOException("Decode without read data."); + } + if (msg != null) { + out.write(msg); + } + off = pos; + } + } while (bis.available() > 0); + } while (readable > 0); + } finally { + if (remaining) { + int len = limit - off; + if (len < buf.length / 2) { + System.arraycopy(buf, off, buf, 0, len); + off = 0; + limit = len; + } + session.setAttribute(BUFFER_KEY, new Object[] { buf, off, limit }); + } else { + session.removeAttribute(BUFFER_KEY); + } + MinaChannel.removeChannelIfDisconnectd(session); + } + } + + public void dispose(IoSession session) throws Exception { + } + + public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception { + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaHandler.java new file mode 100644 index 0000000000..8f23f4d28a --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaHandler.java @@ -0,0 +1,96 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.mina; + +import org.apache.mina.common.IoHandlerAdapter; +import org.apache.mina.common.IoSession; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; + +/** + * MinaHandler + * + * @author william.liangf + */ +public class MinaHandler extends IoHandlerAdapter { + + private final URL url; + + private final ChannelHandler handler; + + public MinaHandler(URL url, ChannelHandler handler) { + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + if (handler == null) { + throw new IllegalArgumentException("handler == null"); + } + this.url = url; + this.handler = handler; + } + + @Override + public void sessionOpened(IoSession session) throws Exception { + MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler); + try { + handler.connected(channel); + } finally { + MinaChannel.removeChannelIfDisconnectd(session); + } + } + + @Override + public void sessionClosed(IoSession session) throws Exception { + MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler); + try { + handler.disconnected(channel); + } finally { + MinaChannel.removeChannelIfDisconnectd(session); + } + } + + @Override + public void messageReceived(IoSession session, Object message) throws Exception { + MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler); + try { + handler.received(channel, message); + } finally { + MinaChannel.removeChannelIfDisconnectd(session); + } + } + + @Override + public void messageSent(IoSession session, Object message) throws Exception { + MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler); + try { + handler.sent(channel, message); + } finally { + MinaChannel.removeChannelIfDisconnectd(session); + } + } + + @Override + public void exceptionCaught(IoSession session, Throwable cause) throws Exception { + MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler); + try { + handler.caught(channel, cause); + } finally { + MinaChannel.removeChannelIfDisconnectd(session); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaServer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaServer.java new file mode 100644 index 0000000000..57b53af100 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaServer.java @@ -0,0 +1,105 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.mina; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Executors; + +import org.apache.mina.common.IoSession; +import org.apache.mina.common.ThreadModel; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.mina.transport.socket.nio.SocketAcceptor; +import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractServer; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelHandlers; + +/** + * MinaServer + * + * @author qian.lei + * @author william.liangf + * @author ding.lid + */ +public class MinaServer extends AbstractServer { + + private SocketAcceptor acceptor; + + public MinaServer(URL url, ChannelHandler handler) throws RemotingException{ + super(url, ChannelHandlers.wrap(handler, url.addParameter(Constants.THREAD_NAME_KEY, SERVER_THREAD_POOL_NAME))); + } + + @Override + protected void doOpen() throws Throwable { + // set thread pool. + acceptor = new SocketAcceptor(getUrl().getPositiveIntParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS), + Executors.newCachedThreadPool(new NamedThreadFactory("MinaServerWorker", + true))); + // config + SocketAcceptorConfig cfg = (SocketAcceptorConfig) acceptor.getDefaultConfig(); + cfg.setThreadModel(ThreadModel.MANUAL); + // set codec. + acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MinaCodecAdapter(getCodec(), getDownstreamCodec(), getUrl(), this))); + + acceptor.bind(getBindAddress(), new MinaHandler(getUrl(), this)); + } + + @Override + protected void doClose() throws Throwable { + try { + if (acceptor != null) { + acceptor.unbind(getBindAddress()); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + public Collection getChannels() { + Set sessions = acceptor.getManagedSessions(getBindAddress()); + Collection channels = new HashSet(); + for (IoSession session : sessions) { + if (session.isConnected()) { + channels.add(MinaChannel.getOrAddChannel(session, getUrl(), this)); + } + } + return channels; + } + + public Channel getChannel(InetSocketAddress remoteAddress) { + Set sessions = acceptor.getManagedSessions(getBindAddress()); + for (IoSession session : sessions) { + if (session.getRemoteAddress().equals(remoteAddress)) { + return MinaChannel.getOrAddChannel(session, getUrl(), this); + } + } + return null; + } + + public boolean isBound() { + return acceptor.isManaged(getBindAddress()); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaTransporter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaTransporter.java new file mode 100644 index 0000000000..482de74887 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/mina/MinaTransporter.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.mina; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.Transporter; + +/** + * @author ding.lid + */ +@Extension(MinaTransporter.NAME) +public class MinaTransporter implements Transporter { + + public static final String NAME = "mina"; + + public Server bind(URL url, ChannelHandler handler) throws RemotingException { + return new MinaServer(url, handler); + } + + public Client connect(URL url, ChannelHandler handler) throws RemotingException { + return new MinaClient(url, handler); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyChannel.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyChannel.java new file mode 100644 index 0000000000..62e77d561a --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyChannel.java @@ -0,0 +1,184 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.netty; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.jboss.netty.channel.ChannelFuture; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractChannel; + +/** + * NettyChannel. + * + * @author qian.lei + * @author william.liangf + */ +final class NettyChannel extends AbstractChannel { + + private static final Logger logger = LoggerFactory.getLogger(NettyChannel.class); + + private static final ConcurrentMap channelMap = new ConcurrentHashMap(); + + private final org.jboss.netty.channel.Channel channel; + + private final Map attributes = new ConcurrentHashMap(); + + private NettyChannel(org.jboss.netty.channel.Channel channel, URL url, ChannelHandler handler){ + super(url, handler); + if (channel == null) { + throw new IllegalArgumentException("netty channel == null;"); + } + this.channel = channel; + } + + static NettyChannel getOrAddChannel(org.jboss.netty.channel.Channel ch, URL url, ChannelHandler handler) { + if (ch == null) { + return null; + } + NettyChannel ret = channelMap.get(ch); + if (ret == null) { + NettyChannel nc = new NettyChannel(ch, url, handler); + if (ch.isConnected()) { + ret = channelMap.putIfAbsent(ch, nc); + } + if (ret == null) { + ret = nc; + } + } + return ret; + } + + static void removeChannelIfDisconnected(org.jboss.netty.channel.Channel ch) { + if (ch != null && ! ch.isConnected()) { + channelMap.remove(ch); + } + } + + public InetSocketAddress getLocalAddress() { + return (InetSocketAddress) channel.getLocalAddress(); + } + + public InetSocketAddress getRemoteAddress() { + return (InetSocketAddress) channel.getRemoteAddress(); + } + + public boolean isConnected() { + return channel.isConnected(); + } + + public void send(Object message, boolean sent) throws RemotingException { + super.send(message, sent); + + boolean success = true; + int timeout = 0; + try { + ChannelFuture future = channel.write(message); + if (sent) { + timeout = getUrl().getPositiveIntParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + success = future.await(timeout); + } + } catch (Throwable e) { + throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e); + } + + if(!success) { + throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + + "in timeout(" + timeout + "ms) limit"); + } + } + + public void close() { + try { + super.close(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + removeChannelIfDisconnected(channel); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + attributes.clear(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + try { + if (logger.isInfoEnabled()) { + logger.info("Close netty channel " + channel); + } + channel.close(); + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + + public boolean hasAttribute(String key) { + return attributes.containsKey(key); + } + + public Object getAttribute(String key) { + return attributes.get(key); + } + + public void setAttribute(String key, Object value) { + if (value == null) { // The null value unallowed in the ConcurrentHashMap. + attributes.remove(key); + } else { + attributes.put(key, value); + } + } + + public void removeAttribute(String key) { + attributes.remove(key); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((channel == null) ? 0 : channel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + NettyChannel other = (NettyChannel) obj; + if (channel == null) { + if (other.channel != null) return false; + } else if (!channel.equals(other.channel)) return false; + return true; + } + + @Override + public String toString() { + return "NettyChannel [channel=" + channel + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyClient.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyClient.java new file mode 100644 index 0000000000..610d100500 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyClient.java @@ -0,0 +1,184 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.netty; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelFutureListener; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.AbstractClient; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelHandlers; + +/** + * NettyClient. + * + * @author qian.lei + * @author william.liangf + */ +public class NettyClient extends AbstractClient { + + // 因ChannelFactory的关闭有DirectMemory泄露,采用静态化规避 + // https://issues.jboss.org/browse/NETTY-424 + private static final ChannelFactory channelFactory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(new NamedThreadFactory("NettyClientBoss", true)), + Executors.newCachedThreadPool(new NamedThreadFactory("NettyClientWorker", true)), + Constants.DEFAULT_IO_THREADS); + private ClientBootstrap bootstrap; + + private volatile Channel channel; // volatile, please copy reference to use + + public NettyClient(final URL url, final ChannelHandler handler) throws RemotingException{ + super(url, wrapChannelHandler(url, handler)); + } + protected static ChannelHandler wrapChannelHandler(URL url, ChannelHandler handler){ + url = url.addParameter(Constants.THREAD_NAME_KEY, CLIENT_THREAD_POOL_NAME) + .addParameter(Constants.THREADPOOL_KEY, Constants.DEFAULT_CLIENT_THREADPOOL); + return ChannelHandlers.wrap(handler, url); + } + @Override + protected void doOpen() throws Throwable { + bootstrap = new ClientBootstrap(channelFactory); + // config + // @see org.jboss.netty.channel.socket.SocketChannelConfig + bootstrap.setOption("keepAlive", true); + bootstrap.setOption("tcpNoDelay", true); + bootstrap.setOption("connectTimeoutMillis", getTimeout()); + final NettyHandler nettyHandler = new NettyHandler(getUrl(), this); + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() { + NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this); + ChannelPipeline pipeline = Channels.pipeline(); + pipeline.addLast("decoder", adapter.getDecoder()); + pipeline.addLast("encoder", adapter.getEncoder()); + pipeline.addLast("handler", nettyHandler); + return pipeline; + } + }); + } + + protected void doConnect() throws Throwable { + ChannelFuture future = bootstrap.connect(getConnectAddress()); + try { + long start = System.currentTimeMillis(); + final AtomicReference exception = new AtomicReference(); + final CountDownLatch finish = new CountDownLatch(1); // resolve future.awaitUninterruptibly() dead lock + future.addListener(new ChannelFutureListener() { + public void operationComplete(ChannelFuture future) throws Exception { + try { + if (future.isSuccess()) { + Channel newChannel = future.getChannel(); + newChannel.setInterestOps(Channel.OP_READ_WRITE); + try { + // 关闭旧的连接 + Channel oldChannel = NettyClient.this.channel; // copy reference + if (oldChannel != null) { + try { + if (logger.isInfoEnabled()) { + logger.info("Close old netty channel " + oldChannel + " on create new netty channel " + newChannel); + } + oldChannel.close(); + } finally { + NettyChannel.removeChannelIfDisconnected(oldChannel); + } + } + } finally { + if (NettyClient.this.isClosed()) { + try { + if (logger.isInfoEnabled()) { + logger.info("Close new netty channel " + newChannel + ", because the client closed."); + } + newChannel.close(); + } finally { + NettyClient.this.channel = null; + NettyChannel.removeChannelIfDisconnected(newChannel); + } + } else { + NettyClient.this.channel = newChannel; + } + } + } else if (future.getCause() != null) { + exception.set(future.getCause()); + } + } catch (Exception e) { + exception.set(e); + } finally { + finish.countDown(); + } + } + }); + try { + finish.await(getConnectTimeout(), TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RemotingException(this, "Failed to connect to server " + getRemoteAddress() + " client-side timeout " + + getConnectTimeout() + "ms (elapsed: " + (System.currentTimeMillis() - start) + + "ms) from netty client " + NetUtils.getLocalHost() + " using dubbo version " + + Version.getVersion() + ", cause: " + e.getMessage(), e); + } + Throwable e = exception.get(); + if (e != null) { + throw e; + } + } finally { + if (! isConnected()) { + future.cancel(); + } + } + } + + @Override + protected void doDisConnect() throws Throwable { + try { + NettyChannel.removeChannelIfDisconnected(channel); + } catch (Throwable t) { + logger.warn(t.getMessage()); + } + } + + @Override + protected void doClose() throws Throwable { + /*try { + bootstrap.releaseExternalResources(); + } catch (Throwable t) { + logger.warn(t.getMessage()); + }*/ + } + + @Override + protected com.alibaba.dubbo.remoting.Channel getChannel() { + Channel c = channel; + if (c == null || ! c.isConnected()) + return null; + return NettyChannel.getOrAddChannel(c, getUrl(), this); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyCodecAdapter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyCodecAdapter.java new file mode 100644 index 0000000000..f3323335a3 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyCodecAdapter.java @@ -0,0 +1,203 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.netty; + +import java.io.IOException; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandler; +import org.jboss.netty.channel.ChannelHandler.Sharable; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.exchange.Response; + +/** + * NettyCodecAdapter. + * + * @author qian.lei + */ +final class NettyCodecAdapter { + + private final ChannelHandler encoder = new InternalEncoder(); + + private final ChannelHandler decoder = new InternalDecoder(); + + private final Codec upstreamCodec; + private final Codec downstreamCodec; + + private final URL url; + + private final int bufferSize; + + private final com.alibaba.dubbo.remoting.ChannelHandler handler; + + public NettyCodecAdapter(Codec codec, URL url, com.alibaba.dubbo.remoting.ChannelHandler handler){ + this(codec, codec, url, handler); + } + /** + * server 端如果有消息发送需要分开codec,默认的上行code是dubbo1兼容的 + */ + public NettyCodecAdapter(Codec upstreamCodec, Codec downstreamCodec, URL url, com.alibaba.dubbo.remoting.ChannelHandler handler){ + this.downstreamCodec = downstreamCodec; + this.upstreamCodec = upstreamCodec; + this.url = url; + this.handler = handler; + int b = url.getPositiveIntParameter(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE); + this.bufferSize = b >= Constants.MIN_BUFFER_SIZE && b <= Constants.MAX_BUFFER_SIZE ? b : Constants.DEFAULT_BUFFER_SIZE; + } + + public ChannelHandler getEncoder() { + return encoder; + } + + public ChannelHandler getDecoder() { + return decoder; + } + + @Sharable + private class InternalEncoder extends OneToOneEncoder { + + @Override + protected Object encode(ChannelHandlerContext ctx, Channel ch, Object msg) throws Exception { + UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(1024); // 不需要关闭 + NettyChannel channel = NettyChannel.getOrAddChannel(ch, url, handler); + try { + if(!(msg instanceof Response)){ + downstreamCodec.encode(channel, os, msg); + }else { + upstreamCodec.encode(channel, os, msg); + } + + } finally { + NettyChannel.removeChannelIfDisconnected(ch); + } + return ChannelBuffers.wrappedBuffer(os.toByteBuffer()); + } + } + + private class InternalDecoder extends SimpleChannelUpstreamHandler { + + private int mOffset = 0, mLimit = 0; + + private byte[] mBuffer = null; + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) throws Exception { + Object o = event.getMessage(); + if (! (o instanceof ChannelBuffer)) { + ctx.sendUpstream(event); + return; + } + + ChannelBuffer input = (ChannelBuffer) o; + int readable = input.readableBytes(); + if (readable <= 0) { + return; + } + + int off, limit; + byte[] buf = mBuffer; + if (buf == null) { + buf = new byte[bufferSize]; + off = limit = 0; + } else { + off = mOffset; + limit = mLimit; + } + + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); + boolean remaining = true; + Object msg; + UnsafeByteArrayInputStream bis; + try { + do { + // read data into buffer. + int read = Math.min(readable, buf.length - limit); + input.readBytes(buf, limit, read); + limit += read; + readable -= read; + bis = new UnsafeByteArrayInputStream(buf, off, limit - off); // 不需要关闭 + // decode object. + do { + try { + msg = upstreamCodec.decode(channel, bis); + } catch (IOException e) { + remaining = false; + throw e; + } + if (msg == Codec.NEED_MORE_INPUT) { + if (off == 0) { + if (readable > 0) { + buf = Bytes.copyOf(buf, buf.length << 1); + } + } else { + int len = limit - off; + System.arraycopy(buf, off, buf, 0, len); // adjust buffer. + off = 0; + limit = len; + } + break; + } else { + int pos = bis.position(); + if (off == pos) { + remaining = false; + throw new IOException("Decode without read data."); + } + if (msg != null) { + Channels.fireMessageReceived(ctx, msg, event.getRemoteAddress()); + } + off = pos; + } + } while (bis.available() > 0); + } while (readable > 0); + } finally { + if (remaining) { + int len = limit - off; + if (len < buf.length / 2) { + System.arraycopy(buf, off, buf, 0, len); + off = 0; + limit = len; + } + mBuffer = buf; + mOffset = off; + mLimit = limit; + } else { + mBuffer = null; + mOffset = mLimit = 0; + } + NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + ctx.sendUpstream(e); + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyHandler.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyHandler.java new file mode 100644 index 0000000000..29421771e9 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyHandler.java @@ -0,0 +1,118 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.netty; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.jboss.netty.channel.ChannelHandler.Sharable; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; + +/** + * NettyHandler + * + * @author william.liangf + */ +@Sharable +public class NettyHandler extends SimpleChannelHandler { + + private final Map channels = new ConcurrentHashMap(); // + + private final URL url; + + private final ChannelHandler handler; + + public NettyHandler(URL url, ChannelHandler handler){ + if (url == null) { + throw new IllegalArgumentException("url == null"); + } + if (handler == null) { + throw new IllegalArgumentException("handler == null"); + } + this.url = url; + this.handler = handler; + } + + public Map getChannels() { + return channels; + } + + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); + try { + if (channel != null) { + channels.put(NetUtils.toAddressString((InetSocketAddress) ctx.getChannel().getRemoteAddress()), channel); + } + handler.connected(channel); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); + } + } + + @Override + public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); + try { + channels.remove(NetUtils.toAddressString((InetSocketAddress) ctx.getChannel().getRemoteAddress())); + handler.disconnected(channel); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); + } + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); + try { + handler.received(channel, e.getMessage()); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); + } + } + + @Override + public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + super.writeRequested(ctx, e); + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); + try { + handler.sent(channel, e.getMessage()); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); + try { + handler.caught(channel, e.getCause()); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyServer.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyServer.java new file mode 100644 index 0000000000..14299cf697 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyServer.java @@ -0,0 +1,152 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.netty; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.transport.support.AbstractServer; +import com.alibaba.dubbo.remoting.transport.support.handler.ChannelHandlers; + +/** + * NettyServer + * + * @author qian.lei + * @author chao.liuc + */ +public class NettyServer extends AbstractServer implements Server { + + private Map channels; // + + private ServerBootstrap bootstrap; + + private org.jboss.netty.channel.Channel channel; + + public NettyServer(URL url, ChannelHandler handler) throws RemotingException{ + super(url, ChannelHandlers.wrap(handler, url.addParameter(Constants.THREAD_NAME_KEY, SERVER_THREAD_POOL_NAME))); + } + + @Override + protected void doOpen() throws Throwable { + ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true)); + ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true)); + ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveIntParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS)); + bootstrap = new ServerBootstrap(channelFactory); + + final NettyHandler nettyHandler = new NettyHandler(getUrl(), this); + channels = nettyHandler.getChannels(); + // https://issues.jboss.org/browse/NETTY-365 + // https://issues.jboss.org/browse/NETTY-379 + // final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true)); + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() { + NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec() ,getDownstreamCodec(), getUrl(), NettyServer.this); + ChannelPipeline pipeline = Channels.pipeline(); + /*int idleTimeout = getIdleTimeout(); + if (idleTimeout > 10000) { + pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0)); + }*/ + pipeline.addLast("decoder", adapter.getDecoder()); + pipeline.addLast("encoder", adapter.getEncoder()); + pipeline.addLast("handler", nettyHandler); + return pipeline; + } + }); + // bind + channel = bootstrap.bind(getBindAddress()); + } + + @Override + protected void doClose() throws Throwable { + try { + if (channel != null) { + // unbind. + channel.close(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + try { + Collection channels = getChannels(); + if (channels != null && channels.size() > 0) { + for (com.alibaba.dubbo.remoting.Channel channel : channels) { + try { + channel.close(); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + try { + if (bootstrap != null) { + // release external resource. + bootstrap.releaseExternalResources(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + try { + if (channels != null) { + channels.clear(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + } + } + + public Collection getChannels() { + Collection chs = new HashSet(); + for (Channel channel : this.channels.values()) { + if (channel.isConnected()) { + chs.add(channel); + } else { + channels.remove(NetUtils.toAddressString(channel.getRemoteAddress())); + } + } + return chs; + } + + public Channel getChannel(InetSocketAddress remoteAddress) { + return channels.get(NetUtils.toAddressString(remoteAddress)); + } + + public boolean isBound() { + return channel.isBound(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyTransporter.java b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyTransporter.java new file mode 100644 index 0000000000..2fc4e4c311 --- /dev/null +++ b/dubbo-remoting/src/main/java/com/alibaba/dubbo/remoting/transport/support/netty/NettyTransporter.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.support.netty; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Client; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.Transporter; + +/** + * @author ding.lid + */ +@Extension(NettyTransporter.NAME) +public class NettyTransporter implements Transporter { + + public static final String NAME = "netty"; + + public Server bind(URL url, ChannelHandler listener) throws RemotingException { + return new NettyServer(url, listener); + } + + public Client connect(URL url, ChannelHandler listener) throws RemotingException { + return new NettyClient(url, listener); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.ChannelHandlerWrapper b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.ChannelHandlerWrapper new file mode 100644 index 0000000000..e5af290238 --- /dev/null +++ b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.ChannelHandlerWrapper @@ -0,0 +1,5 @@ +com.alibaba.dubbo.remoting.transport.support.handler.DefaultChannelHandlerWrapper +com.alibaba.dubbo.remoting.transport.support.handler.DirectChannelHandlerWrapper +com.alibaba.dubbo.remoting.transport.support.handler.ExecutionChannelHandlerWrapper +com.alibaba.dubbo.remoting.transport.support.handler.MessageOnlyChannelHandlerWrapper +com.alibaba.dubbo.remoting.transport.support.handler.ConnectionOrderedChannelHandlerWrapper \ No newline at end of file diff --git a/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Codec b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Codec new file mode 100644 index 0000000000..bed639d2bd --- /dev/null +++ b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Codec @@ -0,0 +1,3 @@ +com.alibaba.dubbo.remoting.transport.codec.TransportCodec +com.alibaba.dubbo.remoting.telnet.codec.TelnetCodec +com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec \ No newline at end of file diff --git a/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Transporter b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Transporter new file mode 100644 index 0000000000..073c772123 --- /dev/null +++ b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Transporter @@ -0,0 +1,3 @@ +com.alibaba.dubbo.remoting.transport.support.netty.NettyTransporter +com.alibaba.dubbo.remoting.transport.support.mina.MinaTransporter +com.alibaba.dubbo.remoting.transport.support.grizzly.GrizzlyTransporter \ No newline at end of file diff --git a/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.exchange.Exchanger b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.exchange.Exchanger new file mode 100644 index 0000000000..6084189450 --- /dev/null +++ b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.exchange.Exchanger @@ -0,0 +1 @@ +com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchanger \ No newline at end of file diff --git a/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.p2p.Networker b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.p2p.Networker new file mode 100644 index 0000000000..cd1e3fc446 --- /dev/null +++ b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.p2p.Networker @@ -0,0 +1,2 @@ +com.alibaba.dubbo.remoting.p2p.support.MulticastNetworker +com.alibaba.dubbo.remoting.p2p.support.FileNetworker \ No newline at end of file diff --git a/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.telnet.TelnetHandler b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.telnet.TelnetHandler new file mode 100644 index 0000000000..cc16268195 --- /dev/null +++ b/dubbo-remoting/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.telnet.TelnetHandler @@ -0,0 +1,4 @@ +com.alibaba.dubbo.remoting.telnet.support.command.ClearTelnetHandler +com.alibaba.dubbo.remoting.telnet.support.command.ExitTelnetHandler +com.alibaba.dubbo.remoting.telnet.support.command.HelpTelnetHandler +com.alibaba.dubbo.remoting.telnet.support.command.StatusTelnetHandler \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ChanelHandlerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ChanelHandlerTest.java new file mode 100644 index 0000000000..93f42ac1b1 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ChanelHandlerTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; + +/** + * ChanelHandlerTest + * + * mvn clean test -Dtest=*PerformanceClientTest -Dserver=10.20.153.187:9911 + * + * @author william.liangf + */ +public class ChanelHandlerTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(ChanelHandlerTest.class); + + @Test + public void testClient() throws Throwable { + // 读取参数 + if (PerformanceUtils.getProperty("server", null) == null) { + logger.warn("Please set -Dserver=127.0.0.1:9911"); + return; + } + final String server = System.getProperty("server", "127.0.0.1:9911"); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + final int timeout = PerformanceUtils.getIntProperty(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + int sleep = PerformanceUtils.getIntProperty("sleep", 60*1000*60); + + final String url = "exchange://" + server + "?transporter=" + transporter + "&serialization=" + serialization + "&timeout=" + timeout; + ExchangeClient exchangeClient =initClient(url); + Thread.sleep(sleep); + closeClient(exchangeClient); + } + + public static ExchangeClient initClient(String url){ + // 创建客户端 + ExchangeClient exchangeClient = null; + PeformanceTestHandler handler = new PeformanceTestHandler(url); + boolean run = true; + while(run){ + try{ + exchangeClient= Exchangers.connect(url,handler); + } catch (Throwable t){ + + if(t!=null && t.getCause()!=null && t.getCause().getClass()!=null && (t.getCause().getClass()==java.net.ConnectException.class + || t.getCause().getClass()== java.net.ConnectException.class)){ + + }else { + t.printStackTrace(); + } + + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (exchangeClient != null) { + run = false; + } + } + return exchangeClient; + } + + public static void closeClient(ExchangeClient client){ + if(client.isConnected()){ + client.close(); + } + } + + static class PeformanceTestHandler extends ExchangeHandlerAdapter{ + String url = ""; + + /** + * @param url + */ + public PeformanceTestHandler(String url) { + this.url = url; + } + + public void connected(Channel channel) throws RemotingException { + System.out.println("connected event,chanel;"+channel); + } + + public void disconnected(Channel channel) throws RemotingException { + System.out.println("disconnected event,chanel;"+channel); + initClient (url); + } + + /* (non-Javadoc) + * @see com.alibaba.dubbo.remoting.transport.support.ChannelHandlerAdapter#caught(com.alibaba.dubbo.remoting.Channel, java.lang.Throwable) + */ + @Override + public void caught(Channel channel, Throwable exception) throws RemotingException { +// System.out.println("caught event:"+exception); + } + + + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ClientReconnectTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ClientReconnectTest.java new file mode 100644 index 0000000000..cff7703983 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ClientReconnectTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; + +/** + * 客户端重连测试 + * @author chao.liuc + * + */ +public class ClientReconnectTest { + @Test + public void testReconnect() throws RemotingException, InterruptedException{ + { + int port = NetUtils.getAvailablePort(); + Client client = startClient(port,200); + Assert.assertEquals(false, client.isConnected()); + Server server = startServer(port); + for(int i=0;i<5;i++){ + Thread.sleep(100); + } + Assert.assertEquals(true, client.isConnected()); + client.close(); + server.close(); + Thread.sleep(1000); + } + { + int port = NetUtils.getAvailablePort(); + Client client = startClient(port, 20000); + Assert.assertEquals(false, client.isConnected()); + Server server = startServer(port); + for(int i=0;i<5;i++){ + Thread.sleep(200); + } + Assert.assertEquals(false, client.isConnected()); + client.close(); + server.close(); + } + } + + public Client startClient(int port , int reconnectPeriod) throws RemotingException{ + final String url = "exchange://127.0.0.1:"+port + "/client.reconnect.test?check=false&"+Constants.RECONNECT_KEY+"="+reconnectPeriod; + return Exchangers.connect(url); + } + + public Server startServer(int port) throws RemotingException{ + final String url = "exchange://127.0.0.1:"+port +"/client.reconnect.test"; + return Exchangers.bind(url, new HandlerAdapter()); + } + + static class HandlerAdapter extends ExchangeHandlerAdapter{ + public void connected(Channel channel) throws RemotingException { + } + public void disconnected(Channel channel) throws RemotingException { + } + public void caught(Channel channel, Throwable exception) throws RemotingException { + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ClientsTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ClientsTest.java new file mode 100644 index 0000000000..3f7fb10405 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/ClientsTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.remoting.transport.support.mina.MinaTransporter; +import com.alibaba.dubbo.remoting.transport.support.netty.NettyTransporter; + +/** + * @author ding.lid + */ +public class ClientsTest { + + @Test + public void testGetTransportEmpty() { + try { + ExtensionLoader.getExtensionLoader(Transporter.class).getExtension(""); + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage(), containsString("Extension name == null")); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testGetTransportNull() { + String name = null; + ExtensionLoader.getExtensionLoader(Transporter.class).getExtension(name); + } + + @Test + public void testGetTransport1() { + String name = "mina"; + assertEquals(MinaTransporter.class, ExtensionLoader.getExtensionLoader(Transporter.class).getExtension(name).getClass()); + } + + @Test + public void testGetTransport3() { + String name = "netty"; + assertEquals(NettyTransporter.class, ExtensionLoader.getExtensionLoader(Transporter.class).getExtension(name).getClass()); + } + + @Test(expected = IllegalStateException.class) + public void testGetTransportWrong() { + String name = "nety"; + assertNull(ExtensionLoader.getExtensionLoader(Transporter.class).getExtension(name).getClass()); + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/DemoService.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/DemoService.java new file mode 100644 index 0000000000..29cadad27c --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/DemoService.java @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +/** + * TestService + */ + +public interface DemoService +{ + void sayHello(String name); + + int plus(int a,int b); +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/DemoServiceImpl.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/DemoServiceImpl.java new file mode 100644 index 0000000000..a9a90e6d7e --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/DemoServiceImpl.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +/** + * TestServiceImpl + */ + +public class DemoServiceImpl implements DemoService +{ + public void sayHello(String name) + { + System.out.println("hello " + name); + } + + public int plus(int a,int b) + { + return a + b; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/Main.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/Main.java new file mode 100644 index 0000000000..f078531d72 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/Main.java @@ -0,0 +1,142 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.io.Serializable; +import java.util.Random; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.remoting.exchange.support.Replier; +import com.alibaba.dubbo.remoting.exchange.support.ReplierDispatcher; + +/** + * Main + */ + +public class Main +{ + public static void main(String[] args) throws Exception + { + startServer(9010); + mutliThreadTest(10,9010); + dataPackageTest(9010); + } + + private static void startServer(int port) throws Exception + { + ReplierDispatcher dispatcher = new ReplierDispatcher(); + dispatcher.addReplier(RpcMessage.class, new RpcMessageHandler()); + dispatcher.addReplier(Object.class, new Replier() { + public Object reply(ExchangeChannel channel, Object msg) + { + for(int i=0;i<10000;i++) + System.currentTimeMillis(); + System.out.println("handle:"+msg+";thread:"+Thread.currentThread().getName()); + return new StringMessage("hello world"); + } + }); + Exchangers.bind(URL.valueOf("dubbo://localhost:" + port), dispatcher); + } + + static void dataPackageTest(int port) throws Exception + { + ExchangeChannel client = Exchangers.connect(URL.valueOf("dubbo://localhost:" + port)); + Random random = new Random(); + for(int i=5;i<100;i++) + { + StringBuilder sb = new StringBuilder(); + for(int j=0;j[]{int.class, int.class},new Object[]{55,25})).get(); + System.out.println("55+25="+result.getResult()); + + for(int i=0;i<100;i++) + client.request(new RpcMessage(DemoService.class.getName(),"sayHello", new Class[]{String.class},new Object[]{"qianlei"+i})); + + for(int i=0;i<100;i++) + client.request(new Main.Data()); + + System.out.println("=====test invoke====="); + for(int i=0;i<100;i++){ + ResponseFuture future = client.request(new Main.Data()); + System.out.println("invoke and get"); + System.out.println("invoke result:" + future.get()); + } + System.out.println("=====the end====="); + } + + static class Data implements Serializable + { + private static final long serialVersionUID = -4666580993978548778L; + + private String mData = ""; + + public Data(){} + + public String getData() + { + return mData; + } + + public void setData(String data) + { + mData = data; + } + } + + static class StringMessage implements Serializable + { + private static final long serialVersionUID = 7193122183120113947L; + + private String mText; + + StringMessage(String msg) + { + mText = msg; + } + + public String toString() + { + return mText; + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/MockResult.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/MockResult.java new file mode 100644 index 0000000000..e8f9376512 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/MockResult.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.io.Serializable; + +/** + * RpcResult. + * + * @author qian.lei + */ + +public class MockResult implements Serializable +{ + private static final long serialVersionUID = -3630485157441794463L; + + private final Object mResult; + + public MockResult(Object result) + { + mResult = result; + } + + public Object getResult() + { + return mResult; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PeerMain.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PeerMain.java new file mode 100644 index 0000000000..a22af9a569 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PeerMain.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.util.Collection; + +import com.alibaba.dubbo.remoting.p2p.Networkers; +import com.alibaba.dubbo.remoting.p2p.Peer; +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerAdapter; + +/** + * PeerMain + * + * @author william.liangf + */ +public class PeerMain { + + public static void main(String[] args) throws Throwable { + String groupURL = "multicast://224.5.6.7:9911"; // 组地址,支持multicast和file两种组 ,可扩展 + final String peerURL = "dubbo://0.0.0.0:" + (((int) (Math.random() * 10000)) + 20000); // 用于交叉组网的本机服务器地址 + + // 加入组,并获取对等引用 + Peer peer = Networkers.join(groupURL, peerURL, new ChannelHandlerAdapter(){ + @Override + public void received(Channel channel, Object message) throws RemotingException { + System.out.println("Received: " + message + " in " + peerURL); + } + }); + + // 向网络中存在的其它对等体发送消息 + for (int i = 0; i < Integer.MAX_VALUE; i ++) { + Collection channels = peer.getChannels(); // 获取与其它所有对等体的通道,此列表动态变化 + if (channels != null && channels.size() > 0) { + for (Channel channel : channels) { + channel.send("(" + i + ") " + peerURL); // 向指定对等体发送消息 + } + } + Thread.sleep(1000); + } + + // 离开网络 + peer.leave(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientCloseTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientCloseTest.java new file mode 100644 index 0000000000..81945626b8 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientCloseTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.Exchangers; + +/** + * ProformanceClient + * 这个测试类会报线程池的异常,因为DefaultChannelHandler中关于线程池的判断产生并发问题(connected事件异步执行,判断已经过了,这时关闭了线程池,然后线程池执行,报错,此问题通过指定Constants.CHANNEL_HANDLER_KEY=connection即可.) + * + * @author william.liangf + */ +public class PerformanceClientCloseTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceClientCloseTest.class); + + @Test + public void testClient() throws Throwable { + // 读取参数 + if (PerformanceUtils.getProperty("server", null) == null) { + logger.warn("Please set -Dserver=127.0.0.1:9911"); + return; + } + final String server = System.getProperty("server", "127.0.0.1:9911"); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + final int timeout = PerformanceUtils.getIntProperty(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + final int concurrent = PerformanceUtils.getIntProperty("concurrent", 1); + final int runs = PerformanceUtils.getIntProperty("runs", Integer.MAX_VALUE); + final String onerror = PerformanceUtils.getProperty("onerror", "continue"); + + final String url = "exchange://" + server + "?transporter=" + transporter + + "&serialization=" + serialization +// + "&"+Constants.CHANNEL_HANDLER_KEY+"=connection" + + "&timeout=" + timeout; + + final AtomicInteger count = new AtomicInteger(); + final AtomicInteger error = new AtomicInteger(); + for (int n = 0; n < concurrent; n++) { + new Thread(new Runnable() { + public void run() { + for (int i = 0; i < runs; i++) { + ExchangeClient client = null; + try { + client = Exchangers.connect(url); + int c = count.incrementAndGet(); + if (c % 100 == 0) { + System.out.println("count: " + count.get() + ", error: " + error.get()); + } + } catch (Exception e) { + error.incrementAndGet(); + e.printStackTrace(); + System.out.println("count: " + count.get() + ", error: " + error.get()); + if ("exit".equals(onerror)) { + System.exit(-1); + } else if ("break".equals(onerror)) { + break; + } else if ("sleep".equals(onerror)) { + try { + Thread.sleep(30000); + } catch (InterruptedException e1) { + } + } + } finally { + if (client != null) { + client.close(); + } + } + } + } + }).start(); + } + synchronized (PerformanceServerTest.class) { + while (true) { + try { + PerformanceServerTest.class.wait(); + } catch (InterruptedException e) { + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientFixedTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientFixedTest.java new file mode 100644 index 0000000000..6b93ca686d --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientFixedTest.java @@ -0,0 +1,136 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.util.ArrayList; +import java.util.Random; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.Exchangers; + +public class PerformanceClientFixedTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceClientTest.class); + + @Test + public void testClient() throws Exception { + // 读取参数 + if (PerformanceUtils.getProperty("server", null) == null) { + logger.warn("Please set -Dserver=127.0.0.1:9911"); + return; + } + final String server = System.getProperty("server", "127.0.0.1:9911"); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + final int timeout = PerformanceUtils.getIntProperty(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + //final int length = PerformanceUtils.getIntProperty("length", 1024); + final int connectionCount = PerformanceUtils.getIntProperty(Constants.CONNECTIONS_KEY, 1); + //final int concurrent = PerformanceUtils.getIntProperty("concurrent", 100); + //int r = PerformanceUtils.getIntProperty("runs", 10000); + //final int runs = r > 0 ? r : Integer.MAX_VALUE; + //final String onerror = PerformanceUtils.getProperty("onerror", "continue"); + final String url = "exchange://" + server + "?transporter=" + transporter + "&serialization=" + serialization + "&timeout=" + timeout; + + //int idx = server.indexOf(':'); + Random rd = new Random(connectionCount); + ArrayList arrays = new ArrayList(); + String oneKBlock = null; + String messageBlock = null; + int s = 0; + int f = 0; + System.out.println("initialize arrays " + url); + while (s < connectionCount) { + ExchangeClient client = null; + try { + System.out.println("open connection " + s + " " + url + arrays.size()); + + client = Exchangers.connect(url); + + System.out.println("run after open"); + + if (client.isConnected()) { + arrays.add(client); + s++; + System.out.println("open client success " + s); + } else { + System.out.println("open client failed, try again."); + } + } catch (Throwable t) { + t.printStackTrace(); + } finally { + if (client != null && client.isConnected() == false) { + f++; + System.out.println("open client failed, try again " + f); + client.close(); + } + } + } + + StringBuilder sb1 = new StringBuilder(); + Random rd2 = new Random(); + char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); + int size1 = numbersAndLetters.length; + for (int j = 0; j < 1024; j++) { + sb1.append(numbersAndLetters[rd2.nextInt(size1)]); + } + oneKBlock = sb1.toString(); + + for (int j = 0; j < Integer.MAX_VALUE; j++) { + try { + String size = "10"; + + int request_size = 10; + try { + request_size = Integer.parseInt(size); + } catch (Throwable t) { + request_size = 10; + } + + if (messageBlock == null) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < request_size; i++) { + sb.append(oneKBlock); + } + messageBlock = sb.toString(); + + System.out.println("set messageBlock to " + messageBlock); + } + int index = rd.nextInt(connectionCount); + ExchangeClient client = arrays.get(index); + // ExchangeClient client = arrays.get(0); + String output = (String) client.request(messageBlock).get(); + + if (output.lastIndexOf(messageBlock) < 0) { + System.out.println("send messageBlock;get " + output); + throw new Throwable("return results invalid"); + } else { + if (j % 100 == 0) + System.out.println("OK: " + j); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientMain.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientMain.java new file mode 100644 index 0000000000..cd56516a23 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientMain.java @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + + +/** + * PerformanceClientMain + */ +public class PerformanceClientMain { + + public static void main(String[] args) throws Throwable { + new PerformanceClientTest().testClient(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientTest.java new file mode 100644 index 0000000000..658de26aac --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceClientTest.java @@ -0,0 +1,228 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; + +/** + * PerformanceClientTest + * + * mvn clean test -Dtest=*PerformanceClientTest -Dserver=10.20.153.187:9911 + * + * @author william.liangf + */ +public class PerformanceClientTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceClientTest.class); + + @Test + @SuppressWarnings("unchecked") + public void testClient() throws Throwable { + // 读取参数 + if (PerformanceUtils.getProperty("server", null) == null) { + logger.warn("Please set -Dserver=127.0.0.1:9911"); + return; + } + final String server = System.getProperty("server", "127.0.0.1:9911"); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + final int timeout = PerformanceUtils.getIntProperty(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + final int length = PerformanceUtils.getIntProperty("length", 1024); + final int connections = PerformanceUtils.getIntProperty(Constants.CONNECTIONS_KEY, 1); + final int concurrent = PerformanceUtils.getIntProperty("concurrent", 100); + int r = PerformanceUtils.getIntProperty("runs", 10000); + final int runs = r > 0 ? r : Integer.MAX_VALUE; + final String onerror = PerformanceUtils.getProperty("onerror", "continue"); + + final String url = "exchange://" + server + "?transporter=" + transporter + "&serialization=" + serialization + "&timeout=" + timeout; + // 创建客户端 + final ExchangeClient[] exchangeClients = new ExchangeClient[connections]; + for (int i = 0; i < connections; i ++) { + //exchangeClients[i] = Exchangers.connect(url,handler); + exchangeClients[i] = Exchangers.connect(url); + } + + List serverEnvironment = (List) exchangeClients[0].request("environment").get(); + List serverScene = (List) exchangeClients[0].request("scene").get(); + + // 制造数据 + StringBuilder buf = new StringBuilder(length); + for (int i = 0; i < length; i ++) { + buf.append("A"); + } + final String data = buf.toString(); + + // 计数器 + final AtomicLong count = new AtomicLong(); + final AtomicLong error = new AtomicLong(); + final AtomicLong time = new AtomicLong(); + final AtomicLong all = new AtomicLong(); + + // 并发调用 + final CountDownLatch latch = new CountDownLatch(concurrent); + for (int i = 0; i < concurrent; i ++) { + new Thread(new Runnable() { + public void run() { + try { + AtomicInteger index = new AtomicInteger(); + long init = System.currentTimeMillis(); + for (int i = 0; i < runs; i++) { + try { + count.incrementAndGet(); + ExchangeClient client = exchangeClients[index.getAndIncrement() % connections]; + long start = System.currentTimeMillis(); + String result = (String) client.request(data).get(); + long end = System.currentTimeMillis(); + if (! data.equals(result)) { + throw new IllegalStateException("Invalid result " + result); + } + time.addAndGet(end - start); + } catch (Exception e) { + error.incrementAndGet(); + e.printStackTrace(); + if ("exit".equals(onerror)) { + System.exit(-1); + } else if ("break".equals(onerror)) { + break; + } else if ("sleep".equals(onerror)) { + try { + Thread.sleep(30000); + } catch (InterruptedException e1) { + } + } + } + } + all.addAndGet(System.currentTimeMillis() - init); + } finally { + latch.countDown(); + } + } + }).start(); + } + + // 输出,tps不精确,但大概反映情况 + new Thread(new Runnable() { + public void run() { + try{ + SimpleDateFormat dateFormat = new SimpleDateFormat ("HH:mm:ss"); + long lastCount = count.get(); + long sleepTime = 2000; + long elapsd = sleepTime/1000; + boolean bfirst = true; + while (latch.getCount() > 0) { + long c = count.get()-lastCount ; + if(! bfirst)//第一次不准 + System.out.println("["+dateFormat.format(new Date()) +"] count: " + count.get() + ", error: " + error.get() + ",tps:"+(c/elapsd)); + + bfirst = false; + lastCount = count.get(); + Thread.sleep(sleepTime); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + }).start(); + + latch.await(); + + for(ExchangeClient client:exchangeClients){ + if(client.isConnected()){ + client.close(); + } + } + + long total = count.get(); + long failed = error.get(); + long succeeded = total - failed; + long elapsed = time.get(); + long allElapsed = all.get(); + long clientElapsed = allElapsed - elapsed; + long art = 0; + long qps = 0; + long throughput = 0; + if (elapsed > 0) { + art = elapsed / succeeded; + qps = concurrent * succeeded * 1000 / elapsed; + throughput = concurrent * succeeded * length * 2 * 1000 / elapsed; + } + + PerformanceUtils.printBorder(); + PerformanceUtils.printHeader("Dubbo Remoting Performance Test Report"); + PerformanceUtils.printBorder(); + PerformanceUtils.printHeader("Test Environment"); + PerformanceUtils.printSeparator(); + for (String item: serverEnvironment) { + PerformanceUtils.printBody("Server " + item); + } + PerformanceUtils.printSeparator(); + List clientEnvironment = PerformanceUtils.getEnvironment(); + for (String item: clientEnvironment) { + PerformanceUtils.printBody("Client " + item); + } + PerformanceUtils.printSeparator(); + PerformanceUtils.printHeader("Test Scene"); + PerformanceUtils.printSeparator(); + for (String item: serverScene) { + PerformanceUtils.printBody("Server " + item); + } + PerformanceUtils.printBody("Client Transporter: " + transporter); + PerformanceUtils.printBody("Serialization: " + serialization); + PerformanceUtils.printBody("Response Timeout: " + timeout + " ms"); + PerformanceUtils.printBody("Data Length: " + length + " bytes"); + PerformanceUtils.printBody("Client Shared Connections: " + connections); + PerformanceUtils.printBody("Client Concurrent Threads: " + concurrent); + PerformanceUtils.printBody("Run Times Per Thread: " + runs); + PerformanceUtils.printSeparator(); + PerformanceUtils.printHeader("Test Result"); + PerformanceUtils.printSeparator(); + PerformanceUtils.printBody("Succeeded Requests: " + DecimalFormat.getIntegerInstance().format(succeeded)); + PerformanceUtils.printBody("Failed Requests: " + failed); + PerformanceUtils.printBody("Client Elapsed Time: " + clientElapsed + " ms"); + PerformanceUtils.printBody("Average Response Time: " + art + " ms"); + PerformanceUtils.printBody("Requests Per Second: " + qps + "/s"); + PerformanceUtils.printBody("Throughput Per Second: " + DecimalFormat.getIntegerInstance().format(throughput) + " bytes/s"); + PerformanceUtils.printBorder(); + } + + static class PeformanceTestHandler extends ExchangeHandlerAdapter{ + + public void connected(Channel channel) throws RemotingException { + System.out.println("connected event,chanel;"+channel); + } + + public void disconnected(Channel channel) throws RemotingException { + System.out.println("disconnected event,chanel;"+channel); + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerMain.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerMain.java new file mode 100644 index 0000000000..a0bd8fa15f --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerMain.java @@ -0,0 +1,29 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +/** + * PerformanceServerMain + * + * @author william.liangf + */ +public class PerformanceServerMain{ + + public static void main(String[] args) throws Exception { + new PerformanceServerTest().testServer(); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java new file mode 100644 index 0000000000..3d770f849e --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java @@ -0,0 +1,163 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; +import com.alibaba.dubbo.remoting.transport.support.handler.ExecutionChannelHandlerWrapper; + +/** + * PerformanceServer + * + * mvn clean test -Dtest=*PerformanceServerTest -Dport=9911 + * + * @author william.liangf + */ +public class PerformanceServerTest extends TestCase { + + private static final Logger logger = LoggerFactory.getLogger(PerformanceServerTest.class); + private static ExchangeServer server = null; + @Test + public void testServer() throws Exception { + // 读取参数 + if (PerformanceUtils.getProperty("port", null) == null) { + logger.warn("Please set -Dport=9911"); + return; + } + final int port = PerformanceUtils.getIntProperty("port", 9911); + final boolean telnet = PerformanceUtils.getBooleanProperty("telnet", true); + if(telnet)statTelnetServer(port+1); + server = statServer(); + + synchronized (PerformanceServerTest.class) { + while (true) { + try { + PerformanceServerTest.class.wait(); + } catch (InterruptedException e) { + } + } + } + } + private static void restartServer(int times,int alive,int sleep) throws Exception{ + if(server!=null && !server.isClosed()){ + server.close(); + Thread.sleep(100); + } + + for(int i=0;i0)Thread.sleep(alive); + server.close(); + if(sleep>0)Thread.sleep(sleep); + } + + server = statServer(); + } + + private static ExchangeServer statServer() throws Exception{ + final int port = PerformanceUtils.getIntProperty("port", 9911); + final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); + final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + final String threadpool = PerformanceUtils.getProperty(Constants.THREADPOOL_KEY, Constants.DEFAULT_THREADPOOL); + final int threads = PerformanceUtils.getIntProperty(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); + final int iothreads = PerformanceUtils.getIntProperty(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS); + final int buffer = PerformanceUtils.getIntProperty(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE); + final String channelHandler = PerformanceUtils.getProperty(Constants.CHANNEL_HANDLER_KEY, ExecutionChannelHandlerWrapper.NAME); + + + // 启动服务器 + ExchangeServer server = Exchangers.bind("exchange://0.0.0.0:" + port + "?transporter=" + + transporter + "&serialization=" + + serialization + "&threadpool=" + threadpool + + "&threads=" + threads + "&iothreads=" + iothreads +"&buffer="+buffer +"&channel.handler="+channelHandler, new ExchangeHandlerAdapter() { + public String telnet(Channel channel, String message) throws RemotingException { + return "echo: " + message + "\r\ntelnet> "; + } + public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + if ("environment".equals(request)) { + return PerformanceUtils.getEnvironment(); + } + if ("scene".equals(request)) { + List scene = new ArrayList(); + scene.add("Transporter: " + transporter); + scene.add("Service Threads: " + threads); + return scene; + } + return request; + } + }); + + return server; + } + + private static ExchangeServer statTelnetServer(int port) throws Exception{ + // 启动服务器 + ExchangeServer telnetserver = Exchangers.bind("exchange://0.0.0.0:" + port , new ExchangeHandlerAdapter() { + public String telnet(Channel channel, String message) throws RemotingException { + if(message.equals("help")){ + return "support cmd: \r\n\tstart \r\n\tstop \r\n\tshutdown \r\n\trestart times [alive] [sleep] \r\ntelnet>"; + } else if(message.equals("stop")){ + logger.info("server closed:"+server); + server.close(); + return "stop server\r\ntelnet>"; + } else if(message.startsWith("start")){ + try { + restartServer(0,0,0); + } catch (Exception e) { + e.printStackTrace(); + } + return "start server\r\ntelnet>"; + } else if(message.startsWith("shutdown")){ + System.exit(0); + return "start server\r\ntelnet>"; + } else if(message.startsWith("channels")){ + return "server.getExchangeChannels():"+server.getExchangeChannels().size()+"\r\ntelnet>"; + } else if(message.startsWith("restart ")){ //r times [sleep] r 10 or r 10 100 + String[] args = message.split(" "); + int times = Integer.parseInt(args[1]); + int alive = args.length>2?Integer.parseInt(args[2]):0; + int sleep = args.length>3?Integer.parseInt(args[3]):100; + try { + restartServer(times,alive,sleep); + } catch (Exception e) { + e.printStackTrace(); + } + + return "restart server,times:"+times+" stop alive time: "+alive+",sleep time: " + sleep+" usage:r times [alive] [sleep] \r\ntelnet>"; + } else{ + return "echo: " + message + "\r\ntelnet> "; + } + + } + }); + + return telnetserver; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceUtils.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceUtils.java new file mode 100644 index 0000000000..f74cc8c224 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/PerformanceUtils.java @@ -0,0 +1,126 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.net.NetworkInterface; +import java.net.SocketException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * PerformanceUtils + * + * @author william.liangf + */ +public class PerformanceUtils { + + public static String getProperty(String key, String defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return value.trim(); + } + + public static int getIntProperty(String key, int defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return Integer.parseInt(value.trim()); + } + public static boolean getBooleanProperty(String key, boolean defaultValue) { + String value = System.getProperty(key); + if (value == null || value.trim().length() == 0 || value.startsWith("$")) { + return defaultValue; + } + return Boolean.parseBoolean(value.trim()); + } + + public static List getEnvironment() { + List environment = new ArrayList(); + environment.add("OS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch", "")); + environment.add("CPU: " + Runtime.getRuntime().availableProcessors() + " cores"); + environment.add("JVM: " + System.getProperty("java.vm.name") + " " + System.getProperty("java.runtime.version")); + environment.add("Memory: " + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().totalMemory()) + + " bytes (Max: " + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().maxMemory()) + " bytes)"); + NetworkInterface ni = PerformanceUtils.getNetworkInterface(); + if (ni != null) { + environment.add("Network: " + ni.getDisplayName()); + } + return environment; + } + + private static final int WIDTH = 64; + + public static void printSeparator() { + StringBuilder pad = new StringBuilder(); + for (int i = 0; i < WIDTH; i ++) { + pad.append("-"); + } + System.out.println("+" + pad + "+"); + } + + public static void printBorder() { + StringBuilder pad = new StringBuilder(); + for (int i = 0; i < WIDTH; i ++) { + pad.append("="); + } + System.out.println("+" + pad + "+"); + } + + public static void printBody(String msg) { + StringBuilder pad = new StringBuilder(); + int len = WIDTH - msg.length() - 1; + if (len > 0) { + for (int i = 0; i < len; i ++) { + pad.append(" "); + } + } + System.out.println("| " + msg + pad + "|"); + } + + public static void printHeader(String msg) { + StringBuilder pad = new StringBuilder(); + int len = WIDTH - msg.length(); + if (len > 0) { + int half = len / 2; + for (int i = 0; i < half; i ++) { + pad.append(" "); + } + } + System.out.println("|" + pad + msg + pad + ((len % 2 == 0) ? "" : " ") + "|"); + } + + public static NetworkInterface getNetworkInterface() { + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (interfaces != null) { + while (interfaces.hasMoreElements()) { + try { + return interfaces.nextElement(); + } catch (Throwable e) { + } + } + } + } catch (SocketException e) { + } + return null; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/RpcMessage.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/RpcMessage.java new file mode 100755 index 0000000000..8ab2c36a8f --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/RpcMessage.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.io.Serializable; + +/** + * RpcMessage. + * + * @author qian.lei + */ + +public class RpcMessage implements Serializable +{ + private static final long serialVersionUID = -5148079121106659095L; + + private String mClassName; + + private String mMethodDesc; + + private Class[] mParameterTypes; + + private Object[] mArguments; + + public RpcMessage(String cn, String desc, Class[] parameterTypes,Object[] args) + { + mClassName = cn; + mMethodDesc = desc; + mParameterTypes = parameterTypes; + mArguments = args; + } + + public String getClassName() + { + return mClassName; + } + + public String getMethodDesc() + { + return mMethodDesc; + } + + public Class[] getParameterTypes() { + return mParameterTypes; + } + + public Object[] getArguments() + { + return mArguments; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/RpcMessageHandler.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/RpcMessageHandler.java new file mode 100755 index 0000000000..0a12593856 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/RpcMessageHandler.java @@ -0,0 +1,90 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import java.lang.reflect.InvocationTargetException; + +import com.alibaba.dubbo.common.bytecode.NoSuchMethodException; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.support.Replier; + +/** + * RpcMessageHandler. + * + * @author qian.lei + */ + +public class RpcMessageHandler implements Replier +{ + public static interface ServiceProvider{ Object getImplementation(String service); } + + private final static ServiceProvider DEFAULT_PROVIDER = new ServiceProvider(){ + public Object getImplementation(String service) + { + String impl = service + "Impl"; + try + { + Class cl = Thread.currentThread().getContextClassLoader().loadClass(impl); + return cl.newInstance(); + } + catch(Exception e) + { + e.printStackTrace(); + } + return null; + } + }; + + private ServiceProvider mProvider; + + public RpcMessageHandler() + { + this(DEFAULT_PROVIDER); + } + + public RpcMessageHandler(ServiceProvider prov) + { + mProvider = prov; + } + + public Class interest() + { + return RpcMessage.class; + } + + public Object reply(ExchangeChannel channel, RpcMessage msg) throws RemotingException + { + String desc = msg.getMethodDesc(); + Object[] args = msg.getArguments(); + Object impl = mProvider.getImplementation(msg.getClassName()); + Wrapper wrap = Wrapper.getWrapper(impl.getClass()); + try + { + return new MockResult(wrap.invokeMethod(impl, desc, msg.getParameterTypes(), args)); + } + catch(NoSuchMethodException e) + { + throw new RemotingException(channel, "Service method not found."); + } + catch(InvocationTargetException e) + { + return new MockResult(e.getTargetException()); + } + + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/TelnetServer.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/TelnetServer.java new file mode 100644 index 0000000000..7ddbb57a0a --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/TelnetServer.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting; + +import com.alibaba.dubbo.remoting.transport.support.ChannelHandlerAdapter; + +/** + * TelnetServer + * + * @author william.liangf + */ +public class TelnetServer { + + public static void main(String[] args) throws Exception { + Transporters.bind("telnet://0.0.0.0:23", new ChannelHandlerAdapter() { + public void connected(Channel channel) throws RemotingException { + channel.send("telnet> "); + } + public void received(Channel channel, Object message) throws RemotingException { + channel.send("Echo: " + message + "\r\n"); + channel.send("telnet> "); + } + }); + // 阻止JVM退出 + synchronized (TelnetServer.class) { + while (true) { + try { + TelnetServer.class.wait(); + } catch (InterruptedException e) { + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/AbstractMockChannel.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/AbstractMockChannel.java new file mode 100644 index 0000000000..1c48dccdd1 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/AbstractMockChannel.java @@ -0,0 +1,121 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.codec; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; + +/** + * @author chao.liuc + * + */ +public class AbstractMockChannel implements Channel { + public static final String LOCAL_ADDRESS = "local"; + public static final String REMOTE_ADDRESS = "remote"; + public static final String ERROR_WHEN_SEND = "error_when_send"; + private URL remoteUrl ; + InetSocketAddress localAddress ; + InetSocketAddress remoteAddress ; + private ChannelHandler handler; + private boolean isClosed ; + private Map attributes = new HashMap(1); + private volatile Object receivedMessage = null; + + public AbstractMockChannel(){ + + } + + public AbstractMockChannel(URL remoteUrl){ + this.remoteUrl = remoteUrl; + this.remoteAddress = NetUtils.toAddress(remoteUrl.getParameter(REMOTE_ADDRESS)); + this.localAddress = NetUtils.toAddress(remoteUrl.getParameter(LOCAL_ADDRESS)); + } + public AbstractMockChannel(ChannelHandler handler){ + this.handler = handler; + } + + public URL getUrl() { + return remoteUrl; + } + + public ChannelHandler getChannelHandler() { + return handler; + } + + public InetSocketAddress getLocalAddress() { + return localAddress ; + } + + public void send(Object message) throws RemotingException { + if (remoteUrl.getBooleanParameter(ERROR_WHEN_SEND, Boolean.FALSE)){ + receivedMessage = null ; + throw new RemotingException(localAddress, remoteAddress, "mock error"); + } else { + receivedMessage = message; + } + } + + public void send(Object message, boolean sent) throws RemotingException { + send(message); + } + + public void close() { + close(0); + } + + public void close(int timeout) { + isClosed = true; + } + + public boolean isClosed() { + return isClosed; + } + + public InetSocketAddress getRemoteAddress() { + return remoteAddress; + } + + public boolean isConnected() { + return isClosed; + } + + public boolean hasAttribute(String key) { + return attributes.containsKey(key); + } + + public Object getAttribute(String key) { + return attributes.get(key); + } + + public void setAttribute(String key, Object value) { + attributes.put(key, value); + } + + public void removeAttribute(String key) { + attributes.remove(key); + } + + public Object getReceivedMessage() { + return receivedMessage; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java new file mode 100644 index 0000000000..93ae7d75b9 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java @@ -0,0 +1,357 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.codec; + + +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.io.Bytes; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.Response; +import com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec; +import com.alibaba.dubbo.remoting.telnet.codec.TelnetCodec; + +/** + * @author chao.liuc + * byte 16 + * 0-1 magic code + * 2 flag + * 8 - 1-request/0-response + * 7 - two way + * 6 - heartbeat + * 1-5 serialization id + * 3 status + * 20 ok + * 90 error? + * 4-11 id (long) + * 12 -15 datalength + * + */ +public class ExchangeCodecTest extends TelnetCodecTest{ + // magic header. + private static final short MAGIC = (short) 0xdabb; + private static final byte MAGIC_HIGH = (byte) Bytes.short2bytes(MAGIC)[0]; + private static final byte MAGIC_LOW = (byte) Bytes.short2bytes(MAGIC)[1]; + Serialization serialization = getSerialization(Constants.DEFAULT_REMOTING_SERIALIZATION); + + + + private Object decode(byte[] request) throws IOException{ + InputStream input = new UnsafeByteArrayInputStream(request); + AbstractMockChannel channel = getServerSideChannel(url); + //decode + Object obj = codec.decode(channel, input); + return obj; + } + + private byte[] getRequestBytes(Object obj, byte[] header) throws IOException{ + // encode request data. + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + ObjectOutput out = serialization.serialize(url, bos); + out.writeObject(obj); + + out.flushBuffer(); + bos.flush(); + bos.close(); + byte[] data = bos.toByteArray(); + byte[] len = Bytes.int2bytes(data.length); + System.arraycopy(len, 0, header, 12, 4); + byte[] request = join(header, data); + return request; + } + + private byte[] assemblyDataProtocol(byte[] header){ + Person request = new Person(); + byte[] newbuf = join(header, objectToByte(request)); + return newbuf; + } + + private static Serialization getSerialization(String name) { + Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(name); + return serialization; + } + //=================================================================================== + + @Before + public void setUp() throws Exception { + codec = new ExchangeCodec(); + } + @Test + public void test_Decode_Error_MagicNum() throws IOException{ + HashMap inputBytes = new HashMap(); + inputBytes.put( new byte[] { 0 }, TelnetCodec.NEED_MORE_INPUT ); + inputBytes.put( new byte[] { MAGIC_HIGH, 0 }, TelnetCodec.NEED_MORE_INPUT ); + inputBytes.put( new byte[] { 0 , MAGIC_LOW }, TelnetCodec.NEED_MORE_INPUT ); + + for (byte[] input : inputBytes.keySet()){ + testDecode_assertEquals(assemblyDataProtocol(input) ,inputBytes.get(input)); + } + } + + @Test + public void test_Decode_Error_Length() throws IOException{ + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, 0x20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + + Channel channel = getServerSideChannel(url); + byte[] baddata = new byte[]{1,2}; + UnsafeByteArrayInputStream input = new UnsafeByteArrayInputStream(join(request, baddata)); + Response obj = (Response)codec.decode(channel, input); + Assert.assertEquals(person, obj.getResult()); + System.out.println(input.available()); + //only decode necessary bytes + Assert.assertEquals(request.length, input.position()); + } + @Test + public void test_Decode_Error_Response_Object() throws IOException{ + //00000010-response/oneway/hearbeat=true |20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, 0x20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + //bad object + byte[] badbytes = new byte[]{-1,-2,-3,-4,-3,-4,-3,-4,-3,-4,-3,-4}; + System.arraycopy(badbytes, 0, request, 21, badbytes.length); + + Response obj = (Response)decode(request); + Assert.assertEquals(90, obj.getStatus()); + } + @Test + public void test_Decode_Check_Payload() throws IOException{ + byte[] header = new byte[] { MAGIC_HIGH , MAGIC_LOW , 1 ,1 ,1 ,1 ,1 , 1 ,1 ,1 ,1 ,1 , 1 ,1 , 1,1 }; + byte[] request = assemblyDataProtocol(header) ; + try{ + testDecode_assertEquals(request, TelnetCodec.NEED_MORE_INPUT); + fail(); + }catch (IOException expected) { + Assert.assertTrue(expected.getMessage().startsWith("Data length too large: "+Bytes.bytes2int(new byte[]{1,1,1,1}))); + } + } + @Test + public void test_Decode_Header_Need_Readmore() throws IOException{ + byte[] header = new byte[] { MAGIC_HIGH , MAGIC_LOW , 0 ,0 ,0 ,0 ,0 , 0 ,0 ,0 ,0 }; + testDecode_assertEquals(header, TelnetCodec.NEED_MORE_INPUT); + } + + @Test + public void test_Decode_Body_Need_Readmore() throws IOException{ + byte[] header = new byte[] { MAGIC_HIGH , MAGIC_LOW , 0 ,0 ,0 ,0 ,0 , 0 ,0 ,0 ,0, 0, 0, 0 , 1 ,1, 'a', 'a' }; + testDecode_assertEquals(header, TelnetCodec.NEED_MORE_INPUT); + } + @Test + public void test_Decode_MigicCodec_Contain_ExchangeHeader() throws IOException{ + // + byte[] header = new byte[] { 0, 0, MAGIC_HIGH , MAGIC_LOW , 0 ,0 ,0 ,0 ,0 , 0 ,0 ,0 ,0 }; + + Channel channel = getServerSideChannel(url); + UnsafeByteArrayInputStream input = new UnsafeByteArrayInputStream(header); + Object obj = codec.decode(channel, input); + Assert.assertEquals(TelnetCodec.NEED_MORE_INPUT, obj); + //如果telnet数据与request数据在同一个数据包中,不能因为telnet没有结尾字符而影响其他数据的接收. + Assert.assertEquals(2, input.position()); + } + + @Test + public void test_Decode_Return_Response_Person() throws IOException{ + //00000010-response/oneway/hearbeat=false/hessian |20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, 2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + + Response obj = (Response)decode(request); + Assert.assertEquals(20, obj.getStatus()); + Assert.assertEquals(person, obj.getResult()); + System.out.println(obj); + } + + @Test //status输入有问题,序列化时读取信息出错. + public void test_Decode_Return_Response_Error() throws IOException{ + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, 2, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + String errorString = "encode request data error "; + byte[] request = getRequestBytes(errorString, header); + Response obj = (Response)decode(request); + Assert.assertEquals(90, obj.getStatus()); + Assert.assertEquals(errorString, obj.getErrorMessage()); + } + @Test + public void test_Decode_Return_Request_Heartbeat_Object() throws IOException{ + //|10011111|20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, (byte) 0xff, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + + Request obj = (Request)decode(request); + Assert.assertEquals(person, obj.getData()); + Assert.assertEquals(true, obj.isTwoWay()); + Assert.assertEquals(true, obj.isHeartbeat()); + Assert.assertEquals("2.0.0", obj.getVersion()); + System.out.println(obj); + } + @Test + public void test_Decode_Return_Request_Object() throws IOException{ + //|10011111|20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, (byte) 0xdf, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + + Request obj = (Request)decode(request); + Assert.assertEquals(person, obj.getData()); + Assert.assertEquals(true, obj.isTwoWay()); + Assert.assertEquals(false, obj.isHeartbeat()); + Assert.assertEquals("2.0.0", obj.getVersion()); + System.out.println(obj); + } + + @Test + public void test_Decode_Error_Request_Object() throws IOException{ + //00000010-response/oneway/hearbeat=true |20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, (byte)0xdf, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + //bad object + byte[] badbytes = new byte[]{-1,-2,-3,-4,-3,-4,-3,-4,-3,-4,-3,-4}; + System.arraycopy(badbytes, 0, request, 21, badbytes.length); + + Request obj = (Request)decode(request); + Assert.assertEquals(true, obj.isBroken()); + Assert.assertEquals(true, obj.getData() instanceof Throwable); + } + + @Test + public void test_Header_Response_NoSerializationFlag() throws IOException{ + //00000010-response/oneway/hearbeat=false/noset |20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + + Response obj = (Response)decode(request); + Assert.assertEquals(20, obj.getStatus()); + Assert.assertEquals(person, obj.getResult()); + System.out.println(obj); + } + + @Test + public void test_Header_Response_Heartbeat() throws IOException{ + //00000010-response/oneway/hearbeat=true |20-stats=ok|id=0|length=0 + byte[] header = new byte[] { MAGIC_HIGH, MAGIC_LOW, 0x20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Person person = new Person(); + byte[] request = getRequestBytes(person, header); + + Response obj = (Response)decode(request); + Assert.assertEquals(20, obj.getStatus()); + Assert.assertEquals(person, obj.getResult()); + System.out.println(obj); + } + + @Test + public void test_Encode_Request() throws IOException{ + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + Channel channel = getCliendSideChannel(url); + Request request = new Request(); + Person person = new Person(); + request.setData(person); + + codec.encode(channel, bos, request); + byte[] data = bos.toByteArray(); + bos.flush(); + bos.close(); + + //encode resault check need decode + InputStream input = new UnsafeByteArrayInputStream(data); + Request obj = (Request)codec.decode(channel, input); + Assert.assertEquals(request.isBroken(), obj.isBroken()); + Assert.assertEquals(request.isHeartbeat(), obj.isHeartbeat()); + Assert.assertEquals(request.isTwoWay(), obj.isTwoWay()); + Assert.assertEquals(person, obj.getData()); + } + + @Test + public void test_Encode_Response() throws IOException{ + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + Channel channel = getCliendSideChannel(url); + Response response = new Response(); + response.setHeartbeat(true); + response.setId(1001l); + response.setStatus((byte)20 ); + response.setVersion("11"); + Person person = new Person(); + response.setResult(person); + + codec.encode(channel, bos, response); + byte[] data = bos.toByteArray(); + bos.flush(); + bos.close(); + + //encode resault check need decode + InputStream input = new UnsafeByteArrayInputStream(data); + Response obj = (Response)codec.decode(channel, input); + + Assert.assertEquals(response.getId(), obj.getId()); + Assert.assertEquals(response.getStatus(), obj.getStatus()); + Assert.assertEquals(response.isHeartbeat(), obj.isHeartbeat()); + Assert.assertEquals(person, obj.getResult()); + // encode response verson ?? +// Assert.assertEquals(response.getVersion(), obj.getVersion()); + + } + + @Test + public void test_Encode_Error_Response() throws IOException{ + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + Channel channel = getCliendSideChannel(url); + Response response = new Response(); + response.setHeartbeat(true); + response.setId(1001l); + response.setStatus((byte)10 ); + response.setVersion("11"); + String badString = "bad" ; + response.setErrorMessage(badString); + Person person = new Person(); + response.setResult(person); + + codec.encode(channel, bos, response); + byte[] data = bos.toByteArray(); + bos.flush(); + bos.close(); + + //encode resault check need decode + InputStream input = new UnsafeByteArrayInputStream(data); + Response obj = (Response)codec.decode(channel, input); + Assert.assertEquals(response.getId(), obj.getId()); + Assert.assertEquals(response.getStatus(), obj.getStatus()); + Assert.assertEquals(response.isHeartbeat(), obj.isHeartbeat()); + Assert.assertEquals(badString, obj.getErrorMessage()); + Assert.assertEquals(null, obj.getResult()); +// Assert.assertEquals(response.getVersion(), obj.getVersion()); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/TelnetCodecTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/TelnetCodecTest.java new file mode 100644 index 0000000000..3176f15187 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/codec/TelnetCodecTest.java @@ -0,0 +1,382 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.codec; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; +import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.telnet.codec.TelnetCodec; + +/** + * @author chao.liuc + * + */ +public class TelnetCodecTest { + protected Codec codec ; + byte[] UP = new byte[] {27, 91, 65}; + byte[] DOWN = new byte[] {27, 91, 66}; + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + codec = new TelnetCodec(); + } + + protected AbstractMockChannel getServerSideChannel(URL url){ + url = url.addParameter(AbstractMockChannel.LOCAL_ADDRESS, url.getAddress()) + .addParameter(AbstractMockChannel.REMOTE_ADDRESS, "127.0.0.1:12345"); + AbstractMockChannel channel = new AbstractMockChannel(url); + return channel; + } + protected AbstractMockChannel getCliendSideChannel(URL url){ + url = url.addParameter(AbstractMockChannel.LOCAL_ADDRESS, "127.0.0.1:12345") + .addParameter(AbstractMockChannel.REMOTE_ADDRESS, url.getAddress()); + AbstractMockChannel channel = new AbstractMockChannel(url); + return channel; + } + + protected byte[] join(byte[] in1, byte[] in2){ + byte[] ret = new byte[in1.length + in2.length]; + System.arraycopy(in1, 0, ret, 0, in1.length); + System.arraycopy(in2, 0, ret, in1.length, in2.length); + return ret; + } + + protected byte[] objectToByte(Object obj){ + byte[] bytes; + if (obj instanceof String){ + bytes = ((String)obj).getBytes(); + } else if (obj instanceof byte[]){ + bytes = (byte[]) obj; + } else { + try { + //object to bytearray + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(bo); + oo.writeObject(obj); + bytes = bo.toByteArray(); + bo.close(); + oo.close(); + } + catch(Exception e){ + throw new RuntimeException(e); + } + } + return(bytes); + } + + protected Object byteToObject(byte[] objBytes) throws Exception { + if (objBytes == null || objBytes.length == 0) { + return null; + } + ByteArrayInputStream bi = new ByteArrayInputStream(objBytes); + ObjectInputStream oi = new ObjectInputStream(bi); + return oi.readObject(); + } + + //====================================================== + public static class Person implements Serializable{ + private static final long serialVersionUID = 3362088148941547337L; + public String name ; + public String sex ; + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((sex == null) ? 0 : sex.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Person other = (Person) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (sex == null) { + if (other.sex != null) + return false; + } else if (!sex.equals(other.sex)) + return false; + return true; + } + + } + + protected void testDecode_assertEquals(byte[] request,Object ret) throws IOException{ + testDecode_assertEquals(request, ret, true); + } + + protected void testDecode_assertEquals(byte[] request,Object ret, boolean isServerside) throws IOException{ + //init channel + Channel channel = isServerside? getServerSideChannel(url) : getCliendSideChannel(url); + //init request string + InputStream input = new UnsafeByteArrayInputStream(request); + + //decode + Object obj = codec.decode(channel, input); + Assert.assertEquals(ret, obj); + } + + + + protected void testEecode_assertEquals(Object request,byte[] ret, boolean isServerside) throws IOException{ + //init channel + Channel channel = isServerside? getServerSideChannel(url) : getCliendSideChannel(url); + + UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024); + + codec.encode(channel, bos, request); + bos.flush(); + bos.close(); + InputStream is = new ByteArrayInputStream(bos.toByteArray()); + byte[] data = new byte[is.available()]; + is.read(data); + + Assert.assertEquals(ret.length, data.length); + for(int i=0;i exitbytes = new HashMap(); + exitbytes.put( new byte[] { 3 }, true ); /* Windows Ctrl+C */ + exitbytes.put( new byte[] { 1, 3 }, false ); //must equal the bytes + exitbytes.put( new byte[] { -1, -12, -1, -3, 6 }, true ); /* Linux Ctrl+C */ + exitbytes.put( new byte[] {1, -1, -12, -1, -3, 6 }, false ); //must equal the bytes + exitbytes.put( new byte[] { -1, -19, -1, -3, 6 }, true ); /* Linux Pause */ + + for (byte[] exit : exitbytes.keySet()){ + testDecode_WithExitByte(exit ,exitbytes.get(exit)); + } + } + @Test + public void testDecode_Backspace() throws IOException{ + //32 8 先加空格在补退格. + testDecode_assertEquals(new byte[]{'\b'}, Codec.NEED_MORE_INPUT, new String(new byte[] {32, 8})); + + //测试中文 + byte[] chineseBytes = "中".getBytes(); + byte[] request = join(chineseBytes, new byte[]{'\b'}); + testDecode_assertEquals(request, Codec.NEED_MORE_INPUT, new String(new byte[] {32, 32, 8, 8})); + //中文会带来此问题 (-数判断) 忽略此问题,退格键只有在真的telnet程序中才输入有意义. + testDecode_assertEquals(new byte[]{'a', 'x', -1, 'x', '\b'}, Codec.NEED_MORE_INPUT, new String(new byte[] {32, 32, 8, 8})); + } + + @Test(expected = IOException.class) + public void testDecode_Backspace_WithError() throws IOException{ + url = url.addParameter(AbstractMockChannel.ERROR_WHEN_SEND, Boolean.TRUE.toString()); + testDecode_Backspace(); + url = url.removeParameter(AbstractMockChannel.ERROR_WHEN_SEND); + } + + @Test() + public void testDecode_History_UP() throws IOException{ + //init channel + AbstractMockChannel channel = getServerSideChannel(url); + + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, null); + + String request1 = "aaa\n"; + Object expected1 = "aaa"; + //init history + testDecode_assertEquals(channel, request1, expected1, null); + + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1); + } + + @Test(expected = IOException.class) + public void testDecode_UPorDOWN_WithError() throws IOException{ + url = url.addParameter(AbstractMockChannel.ERROR_WHEN_SEND, Boolean.TRUE.toString()); + + //init channel + AbstractMockChannel channel = getServerSideChannel(url); + + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, null); + + String request1 = "aaa\n"; + Object expected1 = "aaa"; + //init history + testDecode_assertEquals(channel, request1, expected1, null); + + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1); + + url = url.removeParameter(AbstractMockChannel.ERROR_WHEN_SEND); + } + + @Test() + public void testDecode_History_UP_DOWN_MULTI() throws IOException{ + AbstractMockChannel channel = getServerSideChannel(url); + + String request1 = "aaa\n"; + Object expected1 = request1.replace("\n", ""); + //init history + testDecode_assertEquals(channel, request1, expected1, null); + + String request2 = "bbb\n"; + Object expected2 = request2.replace("\n", ""); + //init history + testDecode_assertEquals(channel, request2, expected2, null); + + String request3 = "ccc\n"; + Object expected3= request3.replace("\n", ""); + //init history + testDecode_assertEquals(channel, request3, expected3, null); + + byte[] UP = new byte[] {27, 91, 65}; + byte[] DOWN = new byte[] {27, 91, 66}; + //history[aaa,bbb,ccc] + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected3); + testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3); + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected2); + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1); + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1); + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1); + testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected2); + testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3); + testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3); + testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3); + testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected2); + } + + + //============================================================================================================================= + @Test + public void testEncode_String_ClientSide() throws IOException{ + testEecode_assertEquals("aaa", "aaa\r\n".getBytes(), false); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/handler/ConnectChannelHandlerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/handler/ConnectChannelHandlerTest.java new file mode 100644 index 0000000000..bb726d043c --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/handler/ConnectChannelHandlerTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.handler; + +import java.util.concurrent.ThreadPoolExecutor; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.remoting.ExecutionException; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.ConnectionOrderedChannelHandler; + + + +public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest{ + + @Before + public void setUp() throws Exception { + handler = new ConnectionOrderedChannelHandler(new BizChannelHander(true), url); + } + + @Test + public void test_Connect_Blocked() throws RemotingException{ + handler = new ConnectionOrderedChannelHandler(new BizChannelHander(false), url); + ThreadPoolExecutor executor = (ThreadPoolExecutor)getField(handler, "connectionExecutor", 1); + Assert.assertEquals(1, executor.getMaximumPoolSize()); + + int runs = 20; + int taskCount = runs * 2; + for(int i=0; i channels = new ConcurrentHashMap(); + ConcurrentHashSet channels = new ConcurrentHashSet(); + + public void connected(Channel channel) throws RemotingException { + channels.add(channel); + } + + public void disconnected(Channel channel) throws RemotingException { + channels.remove(channel); + } + + public void sent(Channel channel, Object message) throws RemotingException { + channel.send(message); + } + + public void received(Channel channel, Object message) throws RemotingException { + //echo + channel.send(message); + } + + public void caught(Channel channel, Throwable exception) throws RemotingException { + throw new RemotingException(channel, exception); + + } + public Set getChannels(){ + return Collections.unmodifiableSet(channels); + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/handler/WrappedChannelHandlerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/handler/WrappedChannelHandlerTest.java new file mode 100644 index 0000000000..cad1599863 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/handler/WrappedChannelHandlerTest.java @@ -0,0 +1,140 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.handler; + + +import static org.junit.Assert.*; + +import java.lang.reflect.Field; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.transport.support.handler.WrappedChannelHandler; + +public class WrappedChannelHandlerTest { + WrappedChannelHandler handler ; + URL url = URL.valueOf("test://10.20.30.40:1234"); + + @Before + public void setUp() throws Exception { + handler = new WrappedChannelHandler(new BizChannelHander(true), url); + } + + @Test + public void test_Execute_Error() throws RemotingException{ + + } + + + protected Object getField(Object obj, String fieldName, int parentdepth){ + try{ + Class clazz = obj.getClass(); + Field field = null; + for(int i=0;i <= parentdepth && field == null ;i++){ + Field[] fields = clazz.getDeclaredFields(); + for(Field f : fields){ + if (f.getName().equals(fieldName)){ + field = f; + break; + } + } + clazz = clazz.getSuperclass(); + } + if (field != null){ + field.setAccessible(true); + return field.get(obj); + }else { + throw new NoSuchFieldException(); + } + }catch (Exception e) { + throw new IllegalStateException(e); + } + } + protected void sleep(int ms){ + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + class BizChannelHander extends MockedChannelHandler{ + private boolean invokeWithBizError; + + public BizChannelHander(boolean invokeWithBizError) { + super(); + this.invokeWithBizError = invokeWithBizError; + } + public BizChannelHander() { + super(); + } + + @Override + public void connected(Channel channel) throws RemotingException { + if (invokeWithBizError){ + throw new RemotingException(channel, "test connect biz error"); + } + sleep(20); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + if (invokeWithBizError){ + throw new RemotingException(channel, "test disconnect biz error"); + } + sleep(20); + } + @Override + public void received(Channel channel, Object message) throws RemotingException { + if (invokeWithBizError){ + throw new RemotingException(channel, "test received biz error"); + } + sleep(20); + } + }; + + class BizException extends RuntimeException{ + private static final long serialVersionUID = -7541893754900723624L; + } + + @Test(expected = RemotingException.class) + public void test_Connect_Biz_Error() throws RemotingException{ + handler.connected(new MockedChannel()); + } + @Test(expected = RemotingException.class) + public void test_Disconnect_Biz_Error() throws RemotingException{ + handler.disconnected(new MockedChannel()); + } + @Test(expected = RemotingException.class) + public void test_MessageReceived_Biz_Error() throws RemotingException{ + handler.received(new MockedChannel(),""); + } + @Test + public void test_Caught_Biz_Error() throws RemotingException{ + try{ + handler.caught(new MockedChannel(), new BizException()); + fail(); + }catch (Exception e) { + Assert.assertEquals(BizException.class, e.getCause().getClass()); + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/ClientToServerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/ClientToServerTest.java new file mode 100644 index 0000000000..f3a5ad46ec --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/ClientToServerTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.junit.Test; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.remoting.exchange.support.Replier; + +/** + * ClientToServer + * + * @author william.liangf + */ +public abstract class ClientToServerTest extends TestCase { + + protected static final String LOCALHOST = "127.0.0.1"; + + protected ExchangeServer server; + + protected ExchangeChannel client; + + protected WorldHandler handler = new WorldHandler(); + + protected abstract ExchangeServer newServer(int port, Replier receiver) throws RemotingException; + + protected abstract ExchangeChannel newClient(int port) throws RemotingException; + + @Override + protected void setUp() throws Exception { + super.setUp(); + int port = (int) (1000 * Math.random() + 10000); + server = newServer(port, handler); + client = newClient(port); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + try { + if (server != null) + server.close(); + } finally { + if (client != null) + client.close(); + } + } + + @Test + public void testFuture() throws Exception { + ResponseFuture future = client.request(new World("world")); + Hello result = (Hello)future.get(); + Assert.assertEquals("hello,world", result.getName()); + } + +// @Test +// public void testCallback() throws Exception { +// final Object waitter = new Object(); +// client.invoke(new World("world"), new InvokeCallback() { +// public void callback(Hello result) { +// Assert.assertEquals("hello,world", result.getName()); +// synchronized (waitter) { +// waitter.notifyAll(); +// } +// } +// public void onException(Throwable exception) { +// } +// }); +// synchronized (waitter) { +// waitter.wait(); +// } +// } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/Hello.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/Hello.java new file mode 100644 index 0000000000..c158d46631 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/Hello.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport; + +import java.io.Serializable; + +/** + * Result + * + * @author william.liangf + */ +public class Hello implements Serializable { + + private static final long serialVersionUID = 8563900571013747774L; + + private String name; + + public Hello() { + } + + public Hello(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/World.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/World.java new file mode 100644 index 0000000000..a62c9acf39 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/World.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport; + +import java.io.Serializable; + +/** + * Data + * + * @author william.liangf + */ +public class World implements Serializable { + + private static final long serialVersionUID = 8563900571013747774L; + + private String name; + + public World() { + } + + public World(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/WorldHandler.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/WorldHandler.java new file mode 100644 index 0000000000..85a1e9ee12 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/WorldHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.support.Replier; + +/** + * DataHandler + * + * @author william.liangf + */ +public class WorldHandler implements Replier { + + public Class interest() { + return World.class; + } + + public Object reply(ExchangeChannel channel, World msg) throws RemotingException { + return new Hello("hello," + msg.getName()); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/mina/MinaClientToServerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/mina/MinaClientToServerTest.java new file mode 100644 index 0000000000..3022b6fc04 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/mina/MinaClientToServerTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.mina; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.Replier; +import com.alibaba.dubbo.remoting.transport.ClientToServerTest; + +/** + * MinaServerClientTest + * + * @author william.liangf + */ +public class MinaClientToServerTest extends ClientToServerTest { + + @Override + protected ExchangeServer newServer(int port, Replier receiver) throws RemotingException { + return Exchangers.bind(URL.valueOf("exchange://localhost:" + port + "?server=mina"), receiver); + } + + @Override + protected ExchangeChannel newClient(int port) throws RemotingException { + return Exchangers.connect(URL.valueOf("exchange://localhost:" + port + "?client=mina")); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyClientTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyClientTest.java new file mode 100644 index 0000000000..ecd869585c --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyClientTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.netty; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.Exchangers; + +/** + * User: heyman + * Date: 5/3/11 + * Time: 5:47 PM + */ +public class NettyClientTest { + static Server server; + + + @BeforeClass + public static void setUp() throws Exception { + /*int port = (int) (1000 * Math.random() + 10000); + //System.out.println(port);*/ + server = Exchangers.bind(URL.valueOf("exchange://localhost:10001?server=netty"), new TelnetServerHandler()); + } + + @Test + public void testClientClose() throws Exception { + List clients = new ArrayList(100); + for (int i = 0; i < 100; i++) { + ExchangeChannel client = Exchangers.connect(URL.valueOf("exchange://localhost:10001?client=netty")); + Thread.sleep(5); + clients.add(client); + } + for (ExchangeChannel client : clients){ + client.close(); + } + Thread.sleep(1000); + } + + @Test + public void testServerClose() throws Exception { + for (int i = 0; i < 100; i++) { + Server aServer = Exchangers.bind(URL.valueOf("exchange://localhost:" + (5000 + i) + "?client=netty"), new TelnetServerHandler()); + System.out.println(i); + aServer.close(); + } + } + + @AfterClass + public static void tearDown() throws Exception { + try { + if (server != null) + server.close(); + } finally { + + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyClientToServerTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyClientToServerTest.java new file mode 100644 index 0000000000..73e41fd774 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyClientToServerTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.netty; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.Replier; +import com.alibaba.dubbo.remoting.transport.ClientToServerTest; + +/** + * NettyClientToServerTest + * + * @author william.liangf + */ +public class NettyClientToServerTest extends ClientToServerTest { + + @Override + protected ExchangeServer newServer(int port, Replier receiver) throws RemotingException { + return Exchangers.bind(URL.valueOf("exchange://localhost:" + port + "?server=netty"), receiver); + } + + @Override + protected ExchangeChannel newClient(int port) throws RemotingException { + return Exchangers.connect(URL.valueOf("exchange://localhost:" + port + "?client=netty")); + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyStringTest.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyStringTest.java new file mode 100644 index 0000000000..dfb8405b06 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/NettyStringTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.netty; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; + +/** + * User: heyman + * Date: 4/26/11 + * Time: 4:13 PM + */ +public class NettyStringTest { + static ExchangeServer server; + static ExchangeChannel client; + + @BeforeClass + public static void setUp() throws Exception { + //int port = (int) (1000 * Math.random() + 10000); + int port = 10001; + System.out.println(port); + server = Exchangers.bind(URL.valueOf("telnet://0.0.0.0:" + port + "?server=netty"), new TelnetServerHandler()); + client = Exchangers.connect(URL.valueOf("telnet://127.0.0.1:" + port + "?client=netty"), new TelnetClientHandler()); + } + + @Test + public void testHandler() throws Exception { + //Thread.sleep(20000); + /*client.request("world\r\n"); + Future future = client.request("world", 10000); + String result = (String)future.get(); + Assert.assertEquals("Did you say 'world'?\r\n",result);*/ + } + + @AfterClass + public static void tearDown() throws Exception { + try { + if (server != null) + server.close(); + } finally { + if (client != null) + client.close(); + } + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/TelnetClientHandler.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/TelnetClientHandler.java new file mode 100644 index 0000000000..9f1aae580f --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/TelnetClientHandler.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.netty; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.support.Replier; + +/** + * User: heyman + * Date: 4/28/11 + * Time: 11:15 AM + */ +public class TelnetClientHandler implements Replier { + + public Class interest() { + return String.class; + } + + public Object reply(ExchangeChannel channel, String msg) throws RemotingException { + return msg; + } +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/TelnetServerHandler.java b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/TelnetServerHandler.java new file mode 100644 index 0000000000..ac5701b240 --- /dev/null +++ b/dubbo-remoting/src/test/java/com/alibaba/dubbo/remoting/transport/netty/TelnetServerHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.remoting.transport.netty; + +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.support.Replier; + +/** + * User: heyman + * Date: 4/26/11 + * Time: 4:29 PM + */ +public class TelnetServerHandler implements Replier { + + public Class interest() { + return String.class; + } + + public Object reply(ExchangeChannel channel, String msg) throws RemotingException { + // Generate and write a response. + + String response; + if (msg.length() == 0) { + response = "Please type something.\r\n"; + } else { + response = "Did you say '" + msg + "'?\r\n"; + } + //System.out.println(response); + return response; + } + +} \ No newline at end of file diff --git a/dubbo-remoting/src/test/resources/log4j.xml b/dubbo-remoting/src/test/resources/log4j.xml new file mode 100644 index 0000000000..8bc0f29a52 --- /dev/null +++ b/dubbo-remoting/src/test/resources/log4j.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-rpc/pom.xml b/dubbo-rpc/pom.xml new file mode 100644 index 0000000000..294d6ccb0e --- /dev/null +++ b/dubbo-rpc/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo-rpc + jar + Dubbo RPC Module + The rpc module of dubbo project + + + com.alibaba + dubbo-remoting + ${project.parent.version} + + + org.apache.mina + mina-core + test + + + \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Exporter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Exporter.java new file mode 100644 index 0000000000..52f759fd70 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Exporter.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +/** + * Exporter. (API/SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.rpc.Protocol#export(Invoker) + * @see com.alibaba.dubbo.rpc.ExporterListener + * @see com.alibaba.dubbo.rpc.support.AbstractExporter + * @author william.liangf + */ +public interface Exporter { + + /** + * get invoker. + * + * @return invoker + */ + Invoker getInvoker(); + + /** + * unexport. + * + * + * getInvoker().destroy(); + * + */ + void unexport(); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/ExporterListener.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/ExporterListener.java new file mode 100644 index 0000000000..0de6536a52 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/ExporterListener.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +/** + * ExporterListener. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +public interface ExporterListener { + + /** + * The exporter exported. + * + * @see com.alibaba.dubbo.rpc.Protocol#export(Invoker) + * @param exporter + * @throws RpcException + */ + void exported(Exporter exporter) throws RpcException; + + /** + * The exporter unexported. + * + * @see com.alibaba.dubbo.rpc.Exporter#unexport() + * @param exporter + * @throws RpcException + */ + void unexported(Exporter exporter); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Filter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Filter.java new file mode 100644 index 0000000000..2a0573f714 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Filter.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import com.alibaba.dubbo.common.Extension; + +/** + * Filter. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +@Extension +public interface Filter { + + /** + * do invoke filter. + * + * + * return invoker.invoke(invocation); + * + * + * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation) + * @param invoker service + * @param invocation invocation. + * @return invoke result. + * @throws RpcException + */ + Result invoke(Invoker invoker, Invocation invocation) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Invocation.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Invocation.java new file mode 100644 index 0000000000..9bda780eb6 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Invocation.java @@ -0,0 +1,59 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.util.Map; + +/** + * Rpc invocation. (API, Prototype, ThreadSafe) + * + * @serial Don't change the class name. + * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation) + * @see com.alibaba.dubbo.rpc.RpcInvocation + * @author qian.lei + * @author william.liangf + */ +public interface Invocation { + + /** + * get method name. + * + * @return method name. + */ + String getMethodName(); + + /** + * get parameter types. + * + * @return parameter types. + */ + Class[] getParameterTypes(); + + /** + * get arguments. + * + * @return arguments. + */ + Object[] getArguments(); + + /** + * get attachments. + * + * @return attachments. + */ + Map getAttachments(); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Invoker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Invoker.java new file mode 100644 index 0000000000..d76ebc7397 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Invoker.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import com.alibaba.dubbo.common.URL; + +/** + * Invoker. (API/SPI, Prototype, ThreadSafe) + * + * @see com.alibaba.dubbo.rpc.Protocol#refer(Class, URL) + * @see com.alibaba.dubbo.rpc.InvokerListener + * @see com.alibaba.dubbo.rpc.support.AbstractInvoker + * @author william.liangf + */ +public interface Invoker { + + /** + * get service interface. + * + * @return service interface. + */ + Class getInterface(); + + /** + * get service url. + * + * @return service url. + */ + URL getUrl(); + + /** + * is available. + * + * @return available. + */ + boolean isAvailable(); + + /** + * invoke. + * + * @param invocation + * @return result + * @throws RpcException + */ + Result invoke(Invocation invocation) throws RpcException; + + /** + * destroy. + */ + void destroy(); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/InvokerListener.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/InvokerListener.java new file mode 100644 index 0000000000..2be31ce45e --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/InvokerListener.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * InvokerListener. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +@Extension +public interface InvokerListener { + + /** + * The invoker referred + * + * @see com.alibaba.dubbo.rpc.Protocol#refer(Class, URL) + * @param invoker + * @throws RpcException + */ + void referred(Invoker invoker) throws RpcException; + + /** + * The invoker destroyed. + * + * @see com.alibaba.dubbo.rpc.Invoker#destroy() + * @param invoker + */ + void destroyed(Invoker invoker); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Protocol.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Protocol.java new file mode 100644 index 0000000000..2158bd3209 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Protocol.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; + +/** + * Protocol. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +@Extension("dubbo") +public interface Protocol { + + /** + * get default port. + * + * @return default port. + */ + int getDefaultPort(); + + /** + * export. + * + * @param + * @param invoker + * @return exporter + * @throws RpcException + */ + @Adaptive + Exporter export(Invoker invoker) throws RpcException; + + /** + * refer. + * + * @param + * @param type + * @param url + * @return invoker + * @throws RpcException + */ + @Adaptive + Invoker refer(Class type, URL url) throws RpcException; + + /** + * destory. + */ + void destroy(); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Result.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Result.java new file mode 100644 index 0000000000..57402cd2c3 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/Result.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +/** + * RPC invoke result. (API, Prototype, ThreadSafe) + * + * @serial Don't change the class name. + * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation) + * @see com.alibaba.dubbo.rpc.RpcResult + * @author qianlei + * @author william.liangf + */ +public interface Result { + + /** + * Has exception. + * + * @return has exception. + */ + boolean hasException(); + + /** + * Get invoke result. + * + * @return result if has exception throw it. + * @throws Throwable. + */ + Object getResult(); + + /** + * Get exception. + * + * @return exception if no exception return null. + */ + Throwable getException(); + + /** + * Recreate. + * + * + * if (hasException()) { + * throw getException(); + * } else { + * return getResult(); + * } + * + */ + Object recreate() throws Throwable; + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcConstants.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcConstants.java new file mode 100644 index 0000000000..d7e320f91b --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcConstants.java @@ -0,0 +1,175 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * RpcConstants + * + * @author william.liangf + */ +public final class RpcConstants { + + public static final List DEFAULT_REFERENCE_FILTERS = Collections.unmodifiableList(Arrays.asList(new String[] { + "consumercontext", "compatible", "deprecated", "collect", "genericimpl", "activelimit", "monitor", "event" })); + + public static final List DEFAULT_SERVICE_FILTERS = Collections.unmodifiableList(Arrays.asList(new String[] { + "ready", "context", "token", "exception", "echo", "generic", "accesslog", "trace", "classloader", "executelimit", "monitor" ,"timeout"})); + + public static final List DEFAULT_INVOKER_LISTENERS = Collections.unmodifiableList(Arrays.asList(new String[] { + "deprecated" })); + + public static final List DEFAULT_EXPORTER_LISTENERS = Collections.unmodifiableList(Arrays.asList(new String[] { })); + + /** + * 集群时是否排除非available的invoker + */ + public static final String CLUSTER_AVAILABLE_CHECK_KEY = "cluster.availablecheck"; + + /** + */ + public static final boolean DEFAULT_CLUSTER_AVAILABLE_CHECK = true; + + /** + * 集群时是否启用sticky策略 + */ + public static final String CLUSTER_STICKY_KEY = "sticky"; + + /** + * sticky默认值. + */ + public static final boolean DEFAULT_CLUSTER_STICKY = false; + + /** + * 创建client时,是否先要建立连接。 + */ + public static final String LAZY_CONNECT_KEY = "lazy"; + + /** + * lazy连接的初始状态是连接状态还是非连接状态? + */ + public static final String LAZY_CONNECT_INITIAL_STATE_KEY = "connect.lazy.initial.state"; + + /** + * lazy连接的初始状态默认是连接状态. + */ + public static final boolean DEFAULT_LAZY_CONNECT_INITIAL_STATE = true; + + /** + * 注册中心是否同步存储文件,默认异步 + */ + public static final String REGISTRY_FILESAVE_SYNC_KEY = "registry.syncsavefile"; + + /** + *注册中心失败事件重试事件 + */ + public static final String REGISTRY_RETRY_FAILED_PERIOD_KEY = "registry.retryfailedperiod"; + + /** + *注册中心自动重连时间 + */ + public static final String REGISTRY_RECONNECT_PERIOD_KEY = "registry.reconnectperiod"; + + /** + * 注册中心导出URL参数的KEY + */ + public static final String EXPORT_KEY = "export"; + + /** + * 注册中心引用URL参数的KEY + */ + public static final String REFER_KEY = "refer"; + + /** + * callback inst id + */ + public static final String CALLBACK_SERVICE_KEY = "callback.service.instid"; + + /** + * 每个客户端同一个接口 callback服务实例的限制 + */ + public static final String CALLBACK_INSTANCES_LIMIT_KEY = "callbacks"; + + /** + * 每个客户端同一个接口 callback服务实例的限制 + */ + public static final int DEFAULT_CALLBACK_INSTANCES = 1; + + public static final String CALLBACK_SERVICE_PROXY_KEY = "callback.service.proxy"; + + public static final String IS_CALLBACK_SERVICE = "is_callback_service"; + + /** + * channel中callback的invokers + */ + public static final String CHANNEL_CALLBACK_KEY = "channel.callback.invokers.key"; + + @Deprecated + public static final String SHUTDOWN_TIMEOUT_SECONDS_KEY = "dubbo.service.shutdown.wait.seconds"; + + public static final String SHUTDOWN_TIMEOUT_KEY = "dubbo.service.shutdown.wait"; + + public static final String IS_SERVER_KEY = "isserver"; + + /** + * 默认值毫秒,避免重新计算. + */ + public static final int DEFAULT_SERVER_SHUTDOWN_TIMEOUT = 10000; + + public static final String ON_CONNECT_KEY = "onconnect"; + + public static final String ON_DISCONNECT_KEY = "ondisconnect"; + + public static final String RETURN_KEY = "return"; + + public static final String ON_INVOKE_METHOD_KEY = "oninvoke.method"; + + public static final String ON_RETURN_METHOD_KEY = "onreturn.method"; + + public static final String ON_THROW_METHOD_KEY = "onthrow.method"; + + public static final String ON_INVOKE_INSTANCE_KEY = "oninvoke.instance"; + + public static final String ON_RETURN_INSTANCE_KEY = "onreturn.instance"; + + public static final String ON_THROW_INSTANCE_KEY = "onthrow.instance"; + + public static final String ROUTE_PROTOCOL = "route"; + + public static final String RULE_KEY = "rule"; + + public static final String TYPE_KEY = "type"; + + // key for router type, for e.g., "script"/"file", corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME + public static final String ROUTER_KEY = "router"; + + // when ROUTER_KEY's value is set to ROUTER_TYPE_CLEAR, RegistryDirectory will clean all current routers + public static final String ROUTER_TYPE_CLEAR = "clean"; + + public static final String DEFAULT_SCRIPT_TYPE_KEY = "javascript"; + + public static final String STUB_EVENT_KEY = "dubbo.stub.event"; + + public static final boolean DEFAULT_STUB_EVENT = false; + + public static final String STUB_EVENT_METHODS_KEY = "dubbo.stub.event.methods"; + + private RpcConstants() {} + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java new file mode 100644 index 0000000000..887072c752 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java @@ -0,0 +1,444 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Future; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; + +/** + * Thread local context. (API, ThreadLocal, ThreadSafe) + * + * @see com.alibaba.dubbo.rpc.filter.ContextFilter + * @see com.alibaba.dubbo.rpc.support.AbstractExporter#invoke(Invocation, InetSocketAddress) + * @author qian.lei + * @author william.liangf + */ +public class RpcContext { + + private static final ThreadLocal LOCAL = new ThreadLocal() { + @Override + protected RpcContext initialValue() { + return new RpcContext(); + } + }; + + /** + * get context. + * + * @return context + */ + public static RpcContext getContext() { + return LOCAL.get(); + } + + /** + * remove context. + * + * @see com.alibaba.dubbo.rpc.filter.ContextFilter + */ + public static void removeContext() { + LOCAL.remove(); + } + + private final Map values = new HashMap(); + + private final Map attachments = new HashMap(); + + private Invoker invoker; + + private Invocation invocation; + + private InetSocketAddress localAddress; + + private InetSocketAddress remoteAddress; + + private Future future; + + protected RpcContext() { + } + + /** + * is server side. + * + * @return server side. + */ + public boolean isServerSide() { + return ! isClientSide(); + } + + /** + * is client side. + * + * @return client side. + */ + public boolean isClientSide() { + Invoker invoker = getInvoker(); + if (invoker == null) { + return false; + } + URL url = invoker.getUrl(); + if (url == null) { + return false; + } + InetSocketAddress address = getRemoteAddress(); + if (address == null) { + return false; + } + String host; + if (address.getAddress() == null) { + host = address.getHostName(); + } else { + host = address.getAddress().getHostAddress(); + } + return url.getPort() == address.getPort() && + NetUtils.filterLocalHost(url.getHost()).equals(NetUtils.filterLocalHost(host)); + } + + /** + * set current invoker. + * + * @param invoker + * @return context + */ + public RpcContext setInvoker(Invoker invoker) { + this.invoker = invoker; + return this; + } + + /** + * get current invoker. + * + * @return invoker + */ + public Invoker getInvoker() { + return invoker; + } + + /** + * set invocation. + * + * @param invocation + * @return context + */ + public RpcContext setInvocation(Invocation invocation) { + this.invocation = invocation; + return this; + } + + /** + * get invocation. + * + * @return invocation + */ + public Invocation getInvocation() { + return invocation; + } + + /** + * set local address. + * + * @param address + * @return context + */ + public RpcContext setLocalAddress(InetSocketAddress address) { + this.localAddress = address; + return this; + } + + /** + * set local address. + * + * @param host + * @param port + * @return context + */ + public RpcContext setLocalAddress(String host, int port) { + if (port < 0) { + port = 0; + } + this.localAddress = InetSocketAddress.createUnresolved(host, port); + return this; + } + + /** + * get local address. + * + * @return local address + */ + public InetSocketAddress getLocalAddress() { + return localAddress; + } + + public String getLocalAddressString() { + return getLocalHost() + ":" + getLocalPort(); + } + + /** + * get local host name. + * + * @return local host name + */ + public String getLocalHostName() { + String host = localAddress == null ? null : localAddress.getHostName(); + if (host == null || host.length() == 0) { + return getLocalHost(); + } + return host; + } + + /** + * set remote address. + * + * @param address + * @return context + */ + public RpcContext setRemoteAddress(InetSocketAddress address) { + this.remoteAddress = address; + return this; + } + + /** + * set remote address. + * + * @param host + * @param port + * @return context + */ + public RpcContext setRemoteAddress(String host, int port) { + if (port < 0) { + port = 0; + } + this.remoteAddress = InetSocketAddress.createUnresolved(host, port); + return this; + } + + /** + * get remote address. + * + * @return remote address + */ + public InetSocketAddress getRemoteAddress() { + return remoteAddress; + } + + /** + * get remote address string. + * + * @return remote address string. + */ + public String getRemoteAddressString() { + return getRemoteHost() + ":" + getRemotePort(); + } + + /** + * get remote host name. + * + * @return remote host name + */ + public String getRemoteHostName() { + return remoteAddress == null ? null : remoteAddress.getHostName(); + } + + /** + * get local host. + * + * @return local host + */ + public String getLocalHost() { + String host = localAddress == null ? null : + localAddress.getAddress() == null ? localAddress.getHostName() + : NetUtils.filterLocalHost(localAddress.getAddress().getHostAddress()); + if (host == null || host.length() == 0) { + return NetUtils.getLocalHost(); + } + return host; + } + + /** + * get local port. + * + * @return port + */ + public int getLocalPort() { + return localAddress == null ? 0 : localAddress.getPort(); + } + + /** + * get remote host. + * + * @return remote host + */ + public String getRemoteHost() { + return remoteAddress == null ? null : + remoteAddress.getAddress() == null ? remoteAddress.getHostName() + : NetUtils.filterLocalHost(remoteAddress.getAddress().getHostAddress()); + } + + /** + * get remote port. + * + * @return remote port + */ + public int getRemotePort() { + return remoteAddress == null ? 0 : remoteAddress.getPort(); + } + + /** + * get values. + * + * @return + */ + public Map get() { + return values; + } + + /** + * set values + * + * @param values + * @return + */ + public RpcContext set(Map value) { + this.values.clear(); + if (value != null && value.size() > 0) { + this.values.putAll(value); + } + return this; + } + + /** + * set value. + * + * @param key + * @param value + * @return context + */ + public RpcContext set(String key, Object value) { + if (value == null) { + values.remove(key); + } else { + values.put(key, value); + } + return this; + } + + /** + * remove value. + * + * @param key + * @return value + */ + public RpcContext remove(String key) { + values.remove(key); + return this; + } + + /** + * get value. + * + * @param key + * @return value + */ + public Object get(String key) { + return values.get(key); + } + + /** + * get attachments. + * + * @return + */ + public Map getAttachments() { + return attachments; + } + + /** + * set attachments + * + * @param attachment + * @return + */ + public RpcContext setAttachments(Map attachment) { + this.attachments.clear(); + if (attachment != null && attachment.size() > 0) { + this.attachments.putAll(attachment); + } + return this; + } + + /** + * set attachment. + * + * @param key + * @param value + * @return + */ + public RpcContext setAttachment(String key, String value) { + if (value == null) { + attachments.remove(key); + } else { + attachments.put(key, value); + } + return this; + } + + /** + * remove attachment. + * + * @param key + * @return + */ + public RpcContext removeAttachment(String key) { + attachments.remove(key); + return this; + } + + /** + * get attachment. + * + * @param key + * @return + */ + public Object getAttachment(String key) { + return attachments.get(key); + } + + /** + * get future. + * + * @param + * @return + */ + @SuppressWarnings("unchecked") + public Future getFuture() { + return (Future) future; + } + + /** + * set future. + * + * @param future + */ + public void setFuture(Future future) { + this.future = future; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcException.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcException.java new file mode 100644 index 0000000000..fa1a3062ae --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcException.java @@ -0,0 +1,103 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +/** + * RPC Exception. (API, Prototype, ThreadSafe) + * + * @serial Don't change the class name and properties. + * @since 1.0 + * @see com.alibaba.dubbo.rpc.Invoker#invoke(RpcInvocation) + * @author shawn.qianx + * @author william.liangf + */ +public class RpcException extends RuntimeException { + + private static final long serialVersionUID = 7815426752583648734L; + + public static final int UNKNOWN_EXCEPTION = 0; + + public static final int NETWORK_EXCEPTION = 1; + + public static final int TIMEOUT_EXCEPTION = 2; + + public static final int BIZ_EXCEPTION = 3; + + public static final int FORBIDDEN_EXCEPTION = 4; + + private int code; + + public RpcException() { + super(); + } + + public RpcException(String message, Throwable cause) { + super(message, cause); + } + + public RpcException(String message) { + super(message); + } + + public RpcException(Throwable cause) { + super(cause); + } + + public RpcException(int code) { + super(); + this.code = code; + } + + public RpcException(int code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public RpcException(int code, String message) { + super(message); + this.code = code; + } + + public RpcException(int code, Throwable cause) { + super(cause); + this.code = code; + } + + public void setCode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public boolean isTimeout() { + return code == TIMEOUT_EXCEPTION; + } + + public boolean isBiz() { + return code == BIZ_EXCEPTION; + } + + public boolean isForbidded() { + return code == FORBIDDEN_EXCEPTION; + } + + public boolean isNetwork() { + return code == NETWORK_EXCEPTION; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java new file mode 100644 index 0000000000..c68dc2fc87 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java @@ -0,0 +1,128 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * Rpc invocation. + * + * @serial Don't change the class name and properties. + * @author qian.lei + */ +public class RpcInvocation implements Invocation, Serializable { + + private static final long serialVersionUID = -4355285085441097045L; + + private String methodName; + + private Class[] parameterTypes; + + private Object[] arguments; + + private Map attachments; + + public RpcInvocation() { + } + + public RpcInvocation(Method method, Object[] arguments) { + this(method.getName(), method.getParameterTypes(), arguments, null); + } + + public RpcInvocation(Method method, Object[] arguments, Map attachment) { + this(method.getName(), method.getParameterTypes(), arguments, attachment); + } + + public RpcInvocation(String methodName, Class[] parameterTypes, Object[] arguments) { + this(methodName, parameterTypes, arguments, null); + } + + public RpcInvocation(String methodName, Class[] parameterTypes, Object[] arguments, Map attachments) { + this.methodName = methodName; + this.parameterTypes = parameterTypes == null ? new Class[0] : parameterTypes; + this.arguments = arguments == null ? new Object[0] : arguments; + this.attachments = attachments == null ? new HashMap() : attachments; + } + + public String getMethodName() { + return methodName; + } + + public Class[] getParameterTypes() { + return parameterTypes; + } + + public Object[] getArguments() { + return arguments; + } + + public Map getAttachments() { + return attachments; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public void setParameterTypes(Class[] parameterTypes) { + this.parameterTypes = parameterTypes == null ? new Class[0] : parameterTypes; + } + + public void setArguments(Object[] arguments) { + this.arguments = arguments == null ? new Object[0] : arguments; + } + + public void setAttachments(Map attachments) { + this.attachments = attachments == null ? new HashMap() : attachments; + } + + public void setAttachment(String key, String value) { + if (attachments == null) { + attachments = new HashMap(); + } + attachments.put(key, value); + } + + public String getAttachment(String key) { + if (attachments == null) { + return null; + } + return attachments.get(key); + } + + public String getAttachment(String key, String defaultValue) { + if (attachments == null) { + return defaultValue; + } + String value = attachments.get(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + return value; + } + + @Override + public String toString() { + return "RpcInvocation [methodName=" + methodName + ", parameterTypes=" + + Arrays.toString(parameterTypes) + ", arguments=" + Arrays.toString(arguments) + + ", attachments=" + attachments + "]"; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java new file mode 100644 index 0000000000..b4c6846d72 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.io.Serializable; + +/** + * Generic rpc invoke result. + * + * @serial Don't change the class name and properties. + * @author qianlei + */ +public class RpcResult implements Result, Serializable { + + private static final long serialVersionUID = -6925924956850004727L; + + private Object result; + + private Throwable exception; + + public RpcResult(){ + } + + public RpcResult(Object result){ + this.result = result; + } + + public RpcResult(Throwable exception){ + this.exception = exception; + } + + public Object recreate() throws Throwable { + if (exception != null) { + throw exception; + } + return result; + } + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + + public Throwable getException() { + return exception; + } + + public void setException(Throwable e) { + this.exception = e; + } + + public boolean hasException() { + return exception != null; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcStatus.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcStatus.java new file mode 100644 index 0000000000..22631dcef8 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/RpcStatus.java @@ -0,0 +1,323 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import com.alibaba.dubbo.common.URL; + +/** + * URL statistics. (API, Cached, ThreadSafe) + * + * @see com.alibaba.dubbo.rpc.filter.CountFilter + * @see com.alibaba.dubbo.rpc.filter.ActiveLimitFilter + * @see com.alibaba.dubbo.routing.loadbalance.LeastActiveLoadBalance + * @author william.liangf + */ +public class RpcStatus { + + private static final ConcurrentMap SERVICE_STATISTICS = new ConcurrentHashMap(); + + private static final ConcurrentMap> METHOD_STATISTICS = new ConcurrentHashMap>(); + + /** + * + * @param url + * @return + */ + public static RpcStatus getStatus(URL url) { + RpcStatus status = SERVICE_STATISTICS.get(url); + if (status == null) { + SERVICE_STATISTICS.putIfAbsent(url, new RpcStatus()); + status = SERVICE_STATISTICS.get(url); + } + return status; + } + + /** + * + * @param url + */ + public static void removeStatus(URL url) { + SERVICE_STATISTICS.remove(url); + } + + /** + * + * @param url + * @param methodName + * @return + */ + public static RpcStatus getStatus(URL url, String methodName) { + ConcurrentMap map = METHOD_STATISTICS.get(url); + if (map == null) { + METHOD_STATISTICS.putIfAbsent(url, new ConcurrentHashMap()); + map = METHOD_STATISTICS.get(url); + } + RpcStatus status = map.get(methodName); + if (status == null) { + map.putIfAbsent(methodName, new RpcStatus()); + status = map.get(methodName); + } + return status; + } + + /** + * + * @param url + */ + public static void removeStatus(URL url, String methodName) { + ConcurrentMap map = METHOD_STATISTICS.get(url); + if (map != null) { + map.remove(methodName); + } + } + + /** + * + * @param url + */ + public static void beginCount(URL url, String methodName) { + beginCount(getStatus(url)); + beginCount(getStatus(url, methodName)); + } + + private static void beginCount(RpcStatus status) { + status.active.incrementAndGet(); + } + + /** + * + * @param url + * @param elapsed + * @param succeeded + */ + public static void endCount(URL url, String methodName, long elapsed, boolean succeeded) { + endCount(getStatus(url), elapsed, succeeded); + endCount(getStatus(url, methodName), elapsed, succeeded); + } + + private static void endCount(RpcStatus status, long elapsed, boolean succeeded) { + status.active.decrementAndGet(); + status.total.incrementAndGet(); + status.totalElapsed.addAndGet(elapsed); + if (status.maxElapsed.get() < elapsed) { + status.maxElapsed.set(elapsed); + } + if (succeeded) { + if (status.succeededMaxElapsed.get() < elapsed) { + status.succeededMaxElapsed.set(elapsed); + } + } else { + status.failed.incrementAndGet(); + status.failedElapsed.addAndGet(elapsed); + if (status.failedMaxElapsed.get() < elapsed) { + status.failedMaxElapsed.set(elapsed); + } + } + } + + private final ConcurrentMap values = new ConcurrentHashMap(); + + private final AtomicInteger active = new AtomicInteger(); + + private final AtomicLong total = new AtomicLong(); + + private final AtomicInteger failed = new AtomicInteger(); + + private final AtomicLong totalElapsed = new AtomicLong(); + + private final AtomicLong failedElapsed = new AtomicLong(); + + private final AtomicLong maxElapsed = new AtomicLong(); + + private final AtomicLong failedMaxElapsed = new AtomicLong(); + + private final AtomicLong succeededMaxElapsed = new AtomicLong(); + + private volatile boolean ready = true; + + private RpcStatus() {} + + /** + * set value. + * + * @param key + * @param value + */ + public void set(String key, Object value) { + values.put(key, value); + } + + /** + * get value. + * + * @param key + * @return value + */ + public Object get(String key) { + return values.get(key); + } + + /** + * get active. + * + * @return active + */ + public int getActive() { + return active.get(); + } + + /** + * get total. + * + * @return total + */ + public long getTotal() { + return total.longValue(); + } + + /** + * get total elapsed. + * + * @return total elapsed + */ + public long getTotalElapsed() { + return totalElapsed.get(); + } + + /** + * get average elapsed. + * + * @return average elapsed + */ + public long getAverageElapsed() { + long total = getTotal(); + if (total == 0) { + return 0; + } + return getTotalElapsed() / total; + } + + /** + * get max elapsed. + * + * @return max elapsed + */ + public long getMaxElapsed() { + return maxElapsed.get(); + } + + /** + * get failed. + * + * @return failed + */ + public int getFailed() { + return failed.get(); + } + + /** + * get failed elapsed. + * + * @return failed elapsed + */ + public long getFailedElapsed() { + return failedElapsed.get(); + } + + /** + * get failed average elapsed. + * + * @return failed average elapsed + */ + public long getFailedAverageElapsed() { + long failed = getFailed(); + if (failed == 0) { + return 0; + } + return getFailedElapsed() / failed; + } + + /** + * get failed max elapsed. + * + * @return failed max elapsed + */ + public long getFailedMaxElapsed() { + return failedMaxElapsed.get(); + } + + /** + * get succeeded. + * + * @return succeeded + */ + public long getSucceeded() { + return getTotal() - getFailed(); + } + + /** + * get succeeded elapsed. + * + * @return succeeded elapsed + */ + public long getSucceededElapsed() { + return getTotalElapsed() - getFailedElapsed(); + } + + /** + * get succeeded average elapsed. + * + * @return succeeded average elapsed + */ + public long getSucceededAverageElapsed() { + long succeeded = getSucceeded(); + if (succeeded == 0) { + return 0; + } + return getSucceededElapsed() / succeeded; + } + + /** + * get succeeded max elapsed. + * + * @return succeeded max elapsed. + */ + public long getSucceededMaxElapsed() { + return succeededMaxElapsed.get(); + } + + /** + * + * @return + */ + public boolean isReady() { + return ready; + } + + /** + * + * @param ready + */ + public void setReady(boolean ready) { + this.ready = ready; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/StaticContext.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/StaticContext.java new file mode 100644 index 0000000000..6a3439845f --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/StaticContext.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * 系统存储,内部类. + */ +public class StaticContext extends ConcurrentHashMap{ + private static final long serialVersionUID = 1L; + private static final String SYSTEMNAME = "system"; + private String name ; + + private static final ConcurrentMap context_map = new ConcurrentHashMap() ; + + private StaticContext(String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + public static StaticContext getSystemContext() { + return getContext(SYSTEMNAME); + } + + public static StaticContext getContext(String name) { + StaticContext appContext = context_map.get(name); + if (appContext == null){ + appContext = context_map.putIfAbsent(name, new StaticContext(name)); + if (appContext == null){ + appContext = context_map.get(name); + } + } + return appContext; + } + public static StaticContext remove(String name){ + return context_map.remove(name); + } + + public static String getKey(URL url, String methodName, String suffix) { + return getKey(url.getServiceKey(), methodName, suffix); + } + public static String getKey(Map paras, String methodName, String suffix) { + return getKey(StringUtils.getServiceKey(paras), methodName, suffix); + } + private static String getKey(String servicekey, String methodName, String suffix) { + StringBuffer sb = new StringBuffer().append(servicekey).append(".").append(methodName).append(".").append(suffix); + return sb.toString(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/CallbackServiceCodec.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/CallbackServiceCodec.java new file mode 100644 index 0000000000..ff23dda0e0 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/CallbackServiceCodec.java @@ -0,0 +1,275 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +/** + * callback 服务帮助类. + * @author chao.liuc + * + */ +public class CallbackServiceCodec { + private static final Logger logger = LoggerFactory.getLogger(CallbackServiceCodec.class); + + private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + private static final DubboProtocol protocol = DubboProtocol.getDubboProtocol(); + private static final byte CALLBACK_NONE = 0x0; + private static final byte CALLBACK_CREATE = 0x1; + private static final byte CALLBACK_DESTROY = 0x2; + private static final String INV_ATT_CALLBACK_KEY = "sys_callback_arg-"; + + private static byte isCallBack(URL url, String methodName ,int argIndex){ + //参数callback的规则是 方法名称.参数index(0开始).callback + byte isCallback = CALLBACK_NONE; + if (url != null ) { + String callback = url.getParameter(methodName+"."+argIndex+".callback"); + if(callback != null) { + if (callback.equalsIgnoreCase("true")) { + isCallback = CALLBACK_CREATE; + }else if(callback.equalsIgnoreCase("false")){ + isCallback = CALLBACK_DESTROY; + } + } + } + return isCallback; + } + + /** + * client 端export callback service + * @param inst + * @param clazz + * @param channel + * @param out + * @param export + * @throws IOException + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static String exportOrunexportCallbackService(Channel channel, Class clazz, Object inst, Boolean export) throws IOException{ + URL url = channel.getUrl(); + int instid = System.identityHashCode(inst); + + Map params = new HashMap(3); + //不需要在重新new client + params.put(RpcConstants.IS_SERVER_KEY, Boolean.FALSE.toString()); + //标识callback 变于排查问题 + params.put(RpcConstants.IS_CALLBACK_SERVICE, Boolean.TRUE.toString()); + String group = url.getParameter(Constants.GROUP_KEY); + if (group != null && group.length() > 0){ + params.put(Constants.GROUP_KEY,group); + } + //增加方法,变于方法检查,自动降级(见dubbo protocol) + params.put(Constants.METHODS_KEY, StringUtils.join(Wrapper.getWrapper(clazz).getDeclaredMethodNames(), ",")); + + Map tmpmap = new HashMap(url.getParameters()); + tmpmap.putAll(params); + tmpmap.remove(Constants.VERSION_KEY);//callback不需要区分version + URL exporturl = new URL(DubboProtocol.NAME, channel.getLocalAddress().getAddress().getHostAddress(), channel.getLocalAddress().getPort(), clazz.getName()+"."+instid, tmpmap); + + //同一个jvm不需要对不同的channel产生多个exporter cache key不会碰撞 + String cacheKey = getClientSideCallbackServiceCacheKey(instid); + String countkey = getClientSideCountKey(clazz.getName()); + if(export){ + //同一个channel 可以有多个callback instance. 不同的instance不重新export + if( ! channel.hasAttribute(cacheKey)){ + if (!isInstancesOverLimit(channel, clazz.getName(), instid, false)) { + Invoker invoker = proxyFactory.getInvoker(inst, clazz, exporturl); + //资源销毁? + Exporter exporter = protocol.export(invoker); + //这个用来记录instid是否发布过服务 + channel.setAttribute(cacheKey, exporter); + logger.info("export a callback service :"+exporturl +", on "+channel + ", url is: " + url); + increaseInstanceCount(channel, countkey); + } + } + }else { + if(channel.hasAttribute(cacheKey)){ + Exporter exporter = (Exporter) channel.getAttribute(cacheKey); + exporter.unexport(); + channel.removeAttribute(cacheKey); + decreaseInstanceCount(channel, countkey); + } + } + return String.valueOf(instid); + } + + /** + * server端 应用一个callbackservice + */ + @SuppressWarnings("unchecked") + private static Object referOrdestroyCallbackService(Channel channel, Class clazz, Invocation inv ,int instid ,boolean isRefer){ + Object proxy = null; + String invokerCacheKey = getServerSideCallbackInvokerCacheKey(channel, instid); + String proxyCacheKey = getServerSideCallbackServiceCacheKey(channel, instid); + proxy = channel.getAttribute(proxyCacheKey) ; + String countkey = getServerSideCountKey(channel, clazz.getName()); + if (isRefer){ + if( proxy == null ){ + if (!isInstancesOverLimit(channel, clazz.getName(), instid, true)){ + @SuppressWarnings("rawtypes") + Invoker invoker = new ChannelWrappedInvoker(clazz, channel, String.valueOf(instid)); + proxy = proxyFactory.getProxy(invoker); + channel.setAttribute(proxyCacheKey, proxy); + channel.setAttribute(invokerCacheKey, invoker); + increaseInstanceCount(channel, countkey); + + //convert error fail fast . + //ignore concurrent problem. + Set> callbackInvokers = (Set>)channel.getAttribute(RpcConstants.CHANNEL_CALLBACK_KEY); + if (callbackInvokers == null){ + callbackInvokers = new ConcurrentHashSet>(1); + callbackInvokers.add(invoker); + channel.setAttribute(RpcConstants.CHANNEL_CALLBACK_KEY, callbackInvokers); + } + logger.info ("method "+inv.getMethodName()+" include a callback service :"+invoker.getUrl() +", a proxy :"+invoker +" has been created.") ; + } + } + } else { + if(proxy != null){ + Invoker invoker = (Invoker)channel.getAttribute(invokerCacheKey); + try{ + Set> callbackInvokers = (Set>)channel.getAttribute(RpcConstants.CHANNEL_CALLBACK_KEY); + if (callbackInvokers != null ) { + callbackInvokers.remove(invoker); + } + invoker.destroy(); + }catch (Exception e) { + logger.error(e); + } + //取消refer 直接在map中去除, + channel.removeAttribute(proxyCacheKey); + channel.removeAttribute(invokerCacheKey); + decreaseInstanceCount(channel,countkey); + } + } + return proxy; + } + + private static String getClientSideCallbackServiceCacheKey(int instid){ + return RpcConstants.CALLBACK_SERVICE_KEY+"."+instid; + } + private static String getServerSideCallbackServiceCacheKey(Channel channel, int instid){ + return RpcConstants.CALLBACK_SERVICE_PROXY_KEY+"."+System.identityHashCode(channel)+"."+instid; + } + private static String getServerSideCallbackInvokerCacheKey(Channel channel, int instid){ + return getServerSideCallbackServiceCacheKey(channel, instid) + "." + "invoker"; + } + + private static String getClientSideCountKey(String interfaceClass){ + return RpcConstants.CALLBACK_SERVICE_KEY+"."+interfaceClass+".COUNT"; + } + private static String getServerSideCountKey(Channel channel, String interfaceClass){ + return RpcConstants.CALLBACK_SERVICE_PROXY_KEY+"."+System.identityHashCode(channel)+"."+interfaceClass+".COUNT"; + } + private static boolean isInstancesOverLimit(Channel channel, String interfaceClass ,int instid, boolean isServer){ + Integer count = (Integer)channel.getAttribute(isServer ? getServerSideCountKey(channel,interfaceClass) : getClientSideCountKey(interfaceClass)); + int limit = channel.getUrl().getIntParameter(RpcConstants.CALLBACK_INSTANCES_LIMIT_KEY, RpcConstants.DEFAULT_CALLBACK_INSTANCES); + if (count != null && count >= limit){ + //client side error + throw new IllegalStateException("interface " + interfaceClass +" `s callback instances num exceed providers limit :"+ limit + +" ,current num: "+(count+1)+". The new callback service will not work !!! you can cancle the callback service which exported before. channel :"+ channel); + }else { + return false; + } + } + private static void increaseInstanceCount(Channel channel, String countkey){ + try{ + //ignore cuncurrent problem? + Integer count = (Integer)channel.getAttribute(countkey); + if (count == null ){ + count = 1; + }else { + count ++ ; + } + channel.setAttribute(countkey, count); + }catch (Exception e) { + logger.error(e); + } + } + private static void decreaseInstanceCount(Channel channel, String countkey){ + try{ + Integer count = (Integer)channel.getAttribute(countkey); + if (count == null || count <= 0){ + return; + }else { + count -- ; + } + channel.setAttribute(countkey, count); + }catch (Exception e) { + logger.error(e); + } + } + + public static Object encodeInvocationArgument(Channel channel, RpcInvocation inv, int paraIndex) throws IOException{ + byte callbackstatus = isCallBack(channel == null ? null : channel.getUrl(), inv.getMethodName(), paraIndex); + Object[] args = inv.getArguments(); + Class[] pts = inv.getParameterTypes(); + switch (callbackstatus) { + case CallbackServiceCodec.CALLBACK_NONE: + return args[paraIndex]; + case CallbackServiceCodec.CALLBACK_CREATE: + inv.setAttachment(INV_ATT_CALLBACK_KEY + paraIndex , exportOrunexportCallbackService(channel, pts[paraIndex], args[paraIndex], true)); + return null; + case CallbackServiceCodec.CALLBACK_DESTROY: + inv.setAttachment(INV_ATT_CALLBACK_KEY + paraIndex, exportOrunexportCallbackService(channel, pts[paraIndex], args[paraIndex], false)); + return null; + default: + return args[paraIndex]; + } + } + public static Object decodeInvocationArgument(Channel channel, RpcInvocation inv, Class[] pts, int paraIndex, Object inObject) throws IOException{ + //如果是callback,则创建proxy到客户端,方法的执行可通过channel调用到client端的callback接口 + byte callbackstatus = isCallBack(channel.getUrl(), inv.getMethodName(), paraIndex); + switch (callbackstatus) { + case CallbackServiceCodec.CALLBACK_NONE: + return inObject; + case CallbackServiceCodec.CALLBACK_CREATE: + try{ + return referOrdestroyCallbackService(channel, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), true); + }catch (Exception e) { + logger.error(e); + throw new IOException(StringUtils.toString(e)); + } + case CallbackServiceCodec.CALLBACK_DESTROY: + try{ + return referOrdestroyCallbackService(channel, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), false); + }catch (Exception e) { + throw new IOException(StringUtils.toString(e)); + } + default: + return inObject ; + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/ChannelWrappedInvoker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/ChannelWrappedInvoker.java new file mode 100644 index 0000000000..a5d6f4329a --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/ChannelWrappedInvoker.java @@ -0,0 +1,172 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.TimeoutException; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeClient; +import com.alibaba.dubbo.remoting.transport.support.ClientDelegate; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.support.AbstractInvoker; + +/** + * 基于已有channel的invoker. + * + * @author chao.liuc + */ +public class ChannelWrappedInvoker extends AbstractInvoker { + + private final Channel channel; + private final String serviceKey ; + + public ChannelWrappedInvoker(Class serviceType, Channel channel, String serviceKey) { + + super(serviceType, channel.getUrl(), new String[] { Constants.GROUP_KEY, + Constants.TOKEN_KEY, Constants.TIMEOUT_KEY }); + this.channel = channel; + this.serviceKey = serviceKey; + } + + @Override + protected Object doInvoke(Invocation invocation) throws Throwable { + RpcInvocation inv = new RpcInvocation(invocation.getMethodName(), + invocation.getParameterTypes(), invocation.getArguments(), + invocation.getAttachments()); + //拿不到client端export 的service path.约定为interface的名称. + inv.setAttachment(Constants.PATH_KEY, getInterface().getName()); + inv.setAttachment(RpcConstants.CALLBACK_SERVICE_KEY, serviceKey); + + ExchangeClient currentClient = new HeaderExchangeClient(new ChannelWrapper(this.channel)); + Result result; + + try { + if (getUrl().getMethodBooleanParameter(invocation.getMethodName(), Constants.ASYNC_KEY)) { // 不可靠异步 + currentClient.send(inv,getUrl().getMethodBooleanParameter(invocation.getMethodName(), Constants.SENT_KEY)); + return null; + } + int timeout = getUrl().getMethodIntParameter(invocation.getMethodName(), + Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + if (timeout > 0) { + result = (Result) currentClient.request(inv, timeout).get(); + } else { + result = (Result) currentClient.request(inv).get(); + } + } catch (RpcException e) { + throw e; + } catch (TimeoutException e) { + throw new RpcException(RpcException.TIMEOUT_EXCEPTION, e.getMessage(), e); + } catch (RemotingException e) { + throw new RpcException(RpcException.NETWORK_EXCEPTION, e.getMessage(), e); + } catch (Throwable e) { // here is non-biz exception, wrap it. + throw new RpcException(e.getMessage(), e); + } + return result.recreate(); + } + + public static class ChannelWrapper extends ClientDelegate { + + private final Channel channel; + private final URL url; + + public ChannelWrapper(Channel channel) { + this.channel = channel; + this.url = channel.getUrl().addParameter("codec", DubboCodec.NAME); + } + + public URL getUrl() { + return url; + } + + public ChannelHandler getChannelHandler() { + return channel.getChannelHandler(); + } + + public InetSocketAddress getLocalAddress() { + return channel.getLocalAddress(); + } + + public void close() { + channel.close(); + } + + public boolean isClosed() { + return channel == null ? true : channel.isClosed(); + } + + public void reset(URL url) { + throw new RpcException("ChannelInvoker can not reset."); + } + + public InetSocketAddress getRemoteAddress() { + return channel.getLocalAddress(); + } + + public boolean isConnected() { + return channel == null ? false : channel.isConnected(); + } + + public boolean hasAttribute(String key) { + return channel.hasAttribute(key); + } + + public Object getAttribute(String key) { + return channel.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + channel.setAttribute(key, value); + } + + public void removeAttribute(String key) { + channel.removeAttribute(key); + } + + public void reconnect() throws RemotingException { + + } + + public void send(Object message) throws RemotingException { + channel.send(message); + } + + public void send(Object message, boolean sent) throws RemotingException { + channel.send(message, sent); + } + + } + + public void destroy() { + //channel资源的清空由channel创建者清除. +// super.destroy(); +// try { +// channel.close(); +// } catch (Throwable t) { +// logger.warn(t.getMessage(), t); +// } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboCodec.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboCodec.java new file mode 100644 index 0000000000..d5b76fc6dd --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboCodec.java @@ -0,0 +1,180 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import static com.alibaba.dubbo.rpc.dubbo.CallbackServiceCodec.decodeInvocationArgument; +import static com.alibaba.dubbo.rpc.dubbo.CallbackServiceCodec.encodeInvocationArgument; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.Codec; +import com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * Dubbo codec. + * + * @author qianlei + * @author chao.liuc + */ +@Extension(value=DubboCodec.NAME) +public class DubboCodec extends ExchangeCodec implements Codec { + public static final String NAME = "dubbo"; + + private static final String DUBBO_VERSION = Version.getVersion(DubboCodec.class, Version.getVersion()); + + private static final byte RESPONSE_WITH_EXCEPTION = 0; + + private static final byte RESPONSE_VALUE = 1; + + private static final byte RESPONSE_NULL_VALUE = 2; + + private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + + + @Override + protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { + RpcInvocation inv = (RpcInvocation) data; + + out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION)); + out.writeUTF(inv.getAttachment(Constants.PATH_KEY)); + out.writeUTF(inv.getAttachment(Constants.VERSION_KEY)); + + out.writeUTF(inv.getMethodName()); + out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes())); + Object[] args = inv.getArguments(); + if (args != null) + for (int i = 0; i < args.length; i++){ + out.writeObject(encodeInvocationArgument(channel, inv, i)); + } + out.writeObject(inv.getAttachments()); + } + + @Override + @SuppressWarnings("unchecked") + protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException { + RpcInvocation inv = new RpcInvocation(); + + inv.setAttachment(Constants.DUBBO_VERSION_KEY, in.readUTF()); + inv.setAttachment(Constants.PATH_KEY, in.readUTF()); + inv.setAttachment(Constants.VERSION_KEY, in.readUTF()); + + inv.setMethodName(in.readUTF()); + try { + Object[] args; + Class[] pts; + String desc = in.readUTF(); + if (desc.length() == 0) { + pts = EMPTY_CLASS_ARRAY; + args = EMPTY_OBJECT_ARRAY; + } else { + pts = ReflectUtils.desc2classArray(desc); + args = new Object[pts.length]; + for (int i = 0; i < args.length; i++){ + try{ + args[i] = in.readObject(pts[i]); + }catch (Exception e) { + e.printStackTrace(); + } + } + } + inv.setParameterTypes(pts); + + Map map = (Map) in.readObject(Map.class); + if (map != null && map.size() > 0) { + Map attachment = inv.getAttachments(); + if (attachment == null) { + attachment = new HashMap(); + } + attachment.putAll(map); + inv.setAttachments(attachment); + } + //decode argument ,may be callback + for (int i = 0; i < args.length; i++){ + args[i] = decodeInvocationArgument(channel, inv, pts, i, args[i]); + } + + inv.setArguments(args); + + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read invocation data failed.", e)); + } + return inv; + } + + @Override + protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException { + Result result = (Result) data; + + Throwable th = result.getException(); + if (th == null) { + Object ret = result.getResult(); + if (ret == null) { + out.writeByte(RESPONSE_NULL_VALUE); + } else { + out.writeByte(RESPONSE_VALUE); + out.writeObject(ret); + } + } else { + out.writeByte(RESPONSE_WITH_EXCEPTION); + out.writeObject(th); + } + } + + @Override + protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException { + RpcResult result = new RpcResult(); + + byte flag = in.readByte(); + switch (flag) { + case RESPONSE_NULL_VALUE: + break; + case RESPONSE_VALUE: + try { + result.setResult(in.readObject()); + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read response data failed.", e)); + } + break; + case RESPONSE_WITH_EXCEPTION: + try { + Object obj = in.readObject(); + if (obj instanceof Throwable == false) throw new IOException("Response data error, expect Throwable, but get " + obj); + result.setException((Throwable) obj); + } catch (ClassNotFoundException e) { + throw new IOException(StringUtils.toString("Read response data failed.", e)); + } + break; + default: + throw new IOException("Unknown result flag, expect '0' '1' '2', get " + flag); + } + return result; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboExporter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboExporter.java new file mode 100644 index 0000000000..38be6d769d --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboExporter.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import java.util.Map; + +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.support.AbstractExporter; + +/** + * DubboExporter + * + * @author william.liangf + */ +public class DubboExporter extends AbstractExporter { + + private final String key; + + private final Map> exporterMap; + + public DubboExporter(Invoker invoker, String key, Map> exporterMap){ + super(invoker); + this.key = key; + this.exporterMap = exporterMap; + } + + @Override + public void unexport() { + super.unexport(); + exporterMap.remove(key); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboInvoker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboInvoker.java new file mode 100644 index 0000000000..f3520e31d3 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboInvoker.java @@ -0,0 +1,136 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.AtomicPositiveInteger; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.TimeoutException; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.support.AbstractInvoker; +import com.alibaba.dubbo.rpc.support.FutureAdapter; + +/** + * DubboInvoker + * + * @author william.liangf + * @author chao.liuc + */ +public class DubboInvoker extends AbstractInvoker { + + private final ExchangeClient[] clients; + + private final AtomicPositiveInteger index = new AtomicPositiveInteger(); + + private final String version; + + public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients){ + super(serviceType, url, new String[] {Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY}); + this.clients = clients; + // get version. + this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0"); + } + + @Override + protected Object doInvoke(final Invocation invocation) throws Throwable { + RpcInvocation inv = null; + final String methodName ; + if(Constants.$INVOKE.equals(invocation.getMethodName()) && invocation.getArguments() !=null && invocation.getArguments().length >0 && invocation.getArguments()[0] != null){ + inv = (RpcInvocation) invocation; + //the frist argument must be real method name; + methodName = invocation.getArguments()[0].toString(); + }else { + inv = new RpcInvocation(invocation.getMethodName(), invocation.getParameterTypes(), + invocation.getArguments(), invocation.getAttachments()); + methodName = invocation.getMethodName(); + } + inv.setAttachment(Constants.PATH_KEY, getUrl().getPath()); + inv.setAttachment(Constants.VERSION_KEY, version); + + ExchangeClient currentClient; + if (clients.length == 1) { + currentClient = clients[0]; + } else { + currentClient = clients[index.getAndIncrement() % clients.length]; + } + Result result = null ; + try { + // 不可靠异步 + boolean isAsync = getUrl().getMethodBooleanParameter(methodName, Constants.ASYNC_KEY); + int timeout = getUrl().getMethodIntParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT); + if (isAsync) { + boolean isReturn = getUrl().getMethodBooleanParameter(methodName, RpcConstants.RETURN_KEY, true); + if (isReturn) { + ResponseFuture future = currentClient.request(inv, timeout) ; + RpcContext.getContext().setFuture(new FutureAdapter(future)); + } else { + boolean isSent = getUrl().getMethodBooleanParameter(methodName, Constants.SENT_KEY); + currentClient.send(inv, isSent); + RpcContext.getContext().setFuture(null); + } + return null; + } + RpcContext.getContext().setFuture(null); + result = (Result) currentClient.request(inv, timeout).get(); + } catch (RpcException e) { + throw e; + } catch (TimeoutException e) { + throw new RpcException(RpcException.TIMEOUT_EXCEPTION, e.getMessage(), e); + } catch (RemotingException e) { + throw new RpcException(RpcException.NETWORK_EXCEPTION, e.getMessage(), e); + } catch (Throwable e) { // here is non-biz exception, wrap it. + throw new RpcException(e.getMessage(), e); + } + //attention: recreate can not in try-catch block. + return result == null ? null: result.recreate(); + } + + @Override + public boolean isAvailable() { + if (!super.isAvailable()) + return false; + if (clients.length ==1){ + return clients[0].isConnected(); + } else { + for (ExchangeClient client : clients){ + if (client.isConnected()){ + return true; + } + } + } + return false; + } + + public void destroy() { + super.destroy(); + for (ExchangeClient client : clients) { + try { + client.close(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboProtocol.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboProtocol.java new file mode 100644 index 0000000000..a56ba650d5 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/DubboProtocol.java @@ -0,0 +1,320 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.Transporter; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.support.AbstractProtocol; + +/** + * dubbo protocol support. + * + * @author qian.lei + * @author william.liangf + * @author chao.liuc + */ +@Extension(DubboProtocol.NAME) +public class DubboProtocol extends AbstractProtocol { + + public static final String NAME = "dubbo"; + + public static final String COMPATIBLE_CODEC_NAME = "dubbo1compatible"; + + public static final int DEFAULT_PORT = 20880; + + private final Map serverMap = new ConcurrentHashMap(); // + + //consumer side export a stub service for dispatching event + //servicekey-stubmethods + private final ConcurrentMap stubServiceMethodsMap = new ConcurrentHashMap(); + + private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() { + private boolean isClientSide(Channel channel) { + InetSocketAddress address = channel.getRemoteAddress(); + URL url = channel.getUrl(); + return url.getPort() == address.getPort() && + NetUtils.filterLocalHost(channel.getUrl().getHost()) + .equals(NetUtils.filterLocalHost(address.getAddress().getHostAddress())); + } + + public Object reply(ExchangeChannel channel, Object message) throws RemotingException { + if (message instanceof Invocation) { + boolean isCallBackServiceInvoke = false; + boolean isStubServiceInvoke = false; + Invocation inv = (Invocation) message; + int port = channel.getLocalAddress().getPort(); + String path = inv.getAttachments().get(Constants.PATH_KEY); + //如果是客户端的回调服务. + isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(RpcConstants.STUB_EVENT_KEY)); + if (isStubServiceInvoke){ + port = channel.getRemoteAddress().getPort(); + } + //callback + isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke; + if(isCallBackServiceInvoke){ + path = inv.getAttachments().get(Constants.PATH_KEY)+"."+inv.getAttachments().get(RpcConstants.CALLBACK_SERVICE_KEY); + } + String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY)); + + DubboExporter exporter = (DubboExporter) exporterMap.get(serviceKey); + + if (exporter == null) + throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:"+message); + + if (isCallBackServiceInvoke){ + String methodsStr = exporter.getInvoker().getUrl().getParameters().get("methods"); + boolean hasMethod = false; + if (methodsStr == null || methodsStr.indexOf(",") == -1){ + hasMethod = inv.getMethodName().equals(methodsStr); + } else { + String[] methods = methodsStr.split(","); + for (String method : methods){ + if (inv.getMethodName().equals(method)){ + hasMethod = true; + break; + } + } + } + if (!hasMethod){ + logger.warn(new IllegalStateException("The methodName "+inv.getMethodName()+" not found in callback service interface ,invoke will be ignored. please update the api interface. url is:" + exporter.getInvoker().getUrl()) +" ,invocation is :"+inv ); + return null; + } + } + + return exporter.invoke(inv, channel.getRemoteAddress()); + } + throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress()); + } + + @Override + public void received(Channel channel, Object message) throws RemotingException { + if (message instanceof Invocation) { + reply((ExchangeChannel) channel, message); + } else { + super.received(channel, message); + } + } + + @Override + public void connected(Channel channel) throws RemotingException { + invoke(channel, RpcConstants.ON_CONNECT_KEY); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + if(logger.isInfoEnabled()){ + logger.info("disconected from "+ channel.getRemoteAddress() + ",url:" + channel.getUrl()); + } + invoke(channel, RpcConstants.ON_DISCONNECT_KEY); + } + + private void invoke(Channel channel, String methodKey) { + Invocation invocation = createInvocation(channel, channel.getUrl(), methodKey); + if (invocation != null) { + try { + received(channel, invocation); + } catch (Throwable t) { + logger.warn("Failed to invoke event method " + invocation.getMethodName() + "(), cause: " + t.getMessage(), t); + } + } + } + + private Invocation createInvocation(Channel channel, URL url, String methodKey) { + String method = url.getParameter(methodKey); + if (method == null || method.length() == 0) { + return null; + } + RpcInvocation invocation = new RpcInvocation(method, new Class[0], new Object[0]); + invocation.setAttachment(Constants.PATH_KEY, url.getPath()); + invocation.setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY)); + invocation.setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY)); + invocation.setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY)); + if (url.getBooleanParameter(RpcConstants.STUB_EVENT_KEY)){ + invocation.setAttachment(RpcConstants.STUB_EVENT_KEY, Boolean.TRUE.toString()); + } + return invocation; + } + }; + + private static DubboProtocol INSTANCE; + + public DubboProtocol() { + INSTANCE = this; + } + + public static DubboProtocol getDubboProtocol() { + if (INSTANCE == null) { + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(DubboProtocol.NAME); // load + } + return INSTANCE; + } + + public Collection getServers() { + return Collections.unmodifiableCollection(serverMap.values()); + } + + public Collection> getExporters() { + return Collections.unmodifiableCollection(exporterMap.values()); + } + + public Collection> getInvokers() { + return Collections.unmodifiableCollection(invokers); + } + + public int getDefaultPort() { + return DEFAULT_PORT; + } + + public Exporter export(Invoker invoker) throws RpcException { + URL url = invoker.getUrl().addParameterIfAbsent(Constants.DOWNSTREAM_CODEC_KEY, DubboCodec.NAME); + // find server. + String key = url.getAddress(); + //client 也可以暴露一个只有server可以调用的服务。 + boolean isServer = url.getBooleanParameter(RpcConstants.IS_SERVER_KEY,true); + if (isServer && ! serverMap.containsKey(key)) { + serverMap.put(key, initServer(url)); + } + // export service. + key = serviceKey(url); + DubboExporter exporter = new DubboExporter(invoker, key, exporterMap); + exporterMap.put(key, exporter); + + //export an stub service for dispaching event + Boolean isStubSupportEvent = url.getBooleanParameter(RpcConstants.STUB_EVENT_KEY,RpcConstants.DEFAULT_STUB_EVENT); + Boolean isCallbackservice = url.getBooleanParameter(RpcConstants.IS_CALLBACK_SERVICE); + if (isStubSupportEvent && !isCallbackservice){ + String stubServiceMethods = url.getParameter(RpcConstants.STUB_EVENT_METHODS_KEY); + if (stubServiceMethods == null || stubServiceMethods.length() == 0 ){ + if (logger.isWarnEnabled()){ + logger.warn( new IllegalStateException("consumer ["+url.getParameter(Constants.INTERFACE_KEY)+"], has set stubproxy support event ,but no stub methods founded.")); + } + } else { + stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); + } + } + return exporter; + } + + private ExchangeServer initServer(URL url) { + String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); + + if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) + throw new RpcException("Unsupported server type: " + str); + + url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME); + ExchangeServer server; + try { + server = Exchangers.bind(url, requestHandler); + } catch (RemotingException e) { + throw new RpcException(e.getMessage(), e); + } + str = url.getParameter(Constants.CLIENT_KEY); + if (str != null && str.length() > 0) { + Set supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(); + if (!supportedTypes.contains(str)) { + throw new RpcException("Unsupported client type: " + str); + } + } + return server; + } + + public Invoker refer(Class serviceType, URL url) throws RpcException { + // find client. + int channels = url.getPositiveIntParameter(Constants.CONNECTIONS_KEY, 1); + ExchangeClient[] clients = new ExchangeClient[channels]; + for (int i = 0; i < clients.length; i++) { + clients[i] = initClient(url); + } + // create rpc invoker. + DubboInvoker invoker = new DubboInvoker(serviceType, url, clients); + invokers.add(invoker); + return invoker; + } + + private ExchangeClient initClient(URL url) { + // client type setting. + String str = url.getParameter(Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_CLIENT)); + + String version = url.getParameter(Constants.DUBBO_VERSION_KEY); + boolean compatible = (version != null && version.startsWith("1.0.")); + url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() && compatible ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME); + + // BIO存在严重性能问题,暂时不允许使用 + if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) { + throw new RpcException("Unsupported client type: " + str + "," + + " supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " ")); + } + + //设置连接应该是lazy的 + if (url.getBooleanParameter(RpcConstants.LAZY_CONNECT_KEY)){ + return new LazyConnectExchangeClient(url ,requestHandler); + } + try { + return Exchangers.connect(url ,requestHandler); + + } catch (RemotingException e) { + throw new RpcException(e.getMessage(), e); + } + } + + public void destroy() { + super.destroy(); + for (String key : new ArrayList(serverMap.keySet())) { + ExchangeServer server = serverMap.remove(key); + if (server != null) { + try { + if (logger.isInfoEnabled()) { + logger.info("Close dubbo server: " + server.getLocalAddress()); + } + server.close(getServerShutdownTimeout()); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + stubServiceMethodsMap.clear(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/LazyConnectExchangeClient.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/LazyConnectExchangeClient.java new file mode 100644 index 0000000000..9c1ea2deb4 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/LazyConnectExchangeClient.java @@ -0,0 +1,179 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + +import java.net.InetSocketAddress; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeClient; +import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeClient; +import com.alibaba.dubbo.rpc.RpcConstants; + +/** + * dubbo protocol support class. + * + * @author chao.liuc + */ +final class LazyConnectExchangeClient implements ExchangeClient { + + private final static Logger logger = LoggerFactory.getLogger(LazyConnectExchangeClient.class); + + private final URL url; + private final ExchangeHandler requestHandler; + private volatile HeaderExchangeClient client; + private final Lock connectLock = new ReentrantLock(); + //lazy connect 如果没有初始化时的连接状态 + private final boolean initialState ; + + public LazyConnectExchangeClient(URL url, ExchangeHandler requestHandler) { + //lazy connect ,need set send.reconnect = true, to avoid channel bad status. + this.url = url.addParameter(Constants.SEND_RECONNECT_KEY, Boolean.TRUE.toString()); + this.requestHandler = requestHandler; + this.initialState = url.getBooleanParameter(RpcConstants.LAZY_CONNECT_INITIAL_STATE_KEY,RpcConstants.DEFAULT_LAZY_CONNECT_INITIAL_STATE); + } + + private void initClient() throws RemotingException { + if (client != null ) + return; + if (logger.isInfoEnabled()) { + logger.info("Lazy connect to " + url); + } + connectLock.lock(); + try { + if (client != null) + return; + this.client = new HeaderExchangeClient(Exchangers.connect(url, requestHandler)); +// if (client == ) + } finally { + connectLock.unlock(); + } + } + + public ResponseFuture request(Object request) throws RemotingException { + initClient(); + return client.request(request); + } + + public URL getUrl() { + return url; + } + + public InetSocketAddress getRemoteAddress() { + return client.getRemoteAddress(); + } + + public ResponseFuture request(Object request, int timeout) throws RemotingException { + initClient(); + return client.request(request, timeout); + } + + public ChannelHandler getChannelHandler() { + checkClient(); + return client.getChannelHandler(); + } + + public boolean isConnected() { + if (client == null) { + return initialState; + } else { + return client.isConnected(); + } + } + + public InetSocketAddress getLocalAddress() { + checkClient(); + return client.getLocalAddress(); + } + + public ExchangeHandler getExchangeHandler() { + checkClient(); + return client.getExchangeHandler(); + } + + public void send(Object message) throws RemotingException { + initClient(); + client.send(message); + } + + public void send(Object message, boolean sent) throws RemotingException { + initClient(); + client.send(message, sent); + } + + public boolean isClosed() { + if (client != null) + return client.isClosed(); + else + return true; + } + + public void close() { + if (client != null) + client.close(); + } + + public void close(int timeout) { + if (client != null) + client.close(timeout); + } + + public void reset(URL url) { + checkClient(); + client.reset(url); + } + + public void reconnect() throws RemotingException { + checkClient(); + client.reconnect(); + } + + public Object getAttribute(String key) { + checkClient(); + return client.getAttribute(key); + } + + public void setAttribute(String key, Object value) { + checkClient(); + client.setAttribute(key, value); + } + + public void removeAttribute(String key) { + checkClient(); + client.removeAttribute(key); + } + + public boolean hasAttribute(String key) { + checkClient(); + return client.hasAttribute(key); + } + + private void checkClient() { + if (client == null) { + throw new IllegalStateException( + "LazyConnectExchangeClient state error. the client has not be init .url:" + url); + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/status/ServerStatusChecker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/status/ServerStatusChecker.java new file mode 100644 index 0000000000..86074d1a73 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/status/ServerStatusChecker.java @@ -0,0 +1,59 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.status; + +import java.util.Collection; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * ServerStatusChecker + * + * @author william.liangf + */ +@Extension("server") +public class ServerStatusChecker implements StatusChecker { + + public Status check() { + Collection servers = DubboProtocol.getDubboProtocol().getServers(); + if (servers == null || servers.size() == 0) { + return new Status(Status.Level.UNKNOWN); + } + Status.Level level = Status.Level.OK; + StringBuilder buf = new StringBuilder(); + for (ExchangeServer server : servers) { + if (! server.isBound()) { + level = Status.Level.ERROR; + buf.setLength(0); + buf.append(server.getLocalAddress()); + break; + } + if (buf.length() > 0) { + buf.append(","); + } + buf.append(server.getLocalAddress()); + buf.append("(clients:"); + buf.append(server.getChannels().size()); + buf.append(")"); + } + return new Status(level, buf.toString()); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/status/ThreadPoolStatusChecker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/status/ThreadPoolStatusChecker.java new file mode 100644 index 0000000000..7529d998ba --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/status/ThreadPoolStatusChecker.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.status; + +import java.util.Collection; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.remoting.ChannelHandler; +import com.alibaba.dubbo.remoting.Server; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeServer; +import com.alibaba.dubbo.remoting.transport.support.handler.WrappedChannelHandler; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * ThreadPoolStatusChecker + * + * @author william.liangf + */ +@Extension("threadpool") +public class ThreadPoolStatusChecker implements StatusChecker { + + public Status check() { + Collection servers = DubboProtocol.getDubboProtocol().getServers(); + if (servers == null || servers.size() == 0) { + return new Status(Status.Level.UNKNOWN); + } + for (Server server : servers) { + if (server instanceof HeaderExchangeServer) { + HeaderExchangeServer exchanger = (HeaderExchangeServer) server; + server = exchanger.getServer(); + } + ChannelHandler handler = server.getChannelHandler(); + if (handler instanceof WrappedChannelHandler) { + Executor executor = ((WrappedChannelHandler) handler).getExecutor(); + if (executor instanceof ThreadPoolExecutor) { + ThreadPoolExecutor tp = (ThreadPoolExecutor)executor; + boolean ok = tp.getActiveCount() < tp.getMaximumPoolSize() - 1; + return new Status(ok ? Status.Level.OK : Status.Level.WARN, + "max:" + tp.getMaximumPoolSize() + + ",core:" + tp.getCorePoolSize() + + ",largest:" + tp.getLargestPoolSize() + + ",active:" + tp.getActiveCount() + + ",task:" + tp.getTaskCount()); + } + } + } + return new Status(Status.Level.UNKNOWN); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/ChangeTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/ChangeTelnetHandler.java new file mode 100644 index 0000000000..20aac2bea7 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/ChangeTelnetHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * ChangeServiceTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[service]", summary = "Change default service.", detail = "Change default service.") +@Extension("cd") +public class ChangeTelnetHandler implements TelnetHandler { + + public static final String SERVICE_KEY = "telnet.service"; + + public String telnet(Channel channel, String message) { + if (message == null || message.length() == 0) { + return "Please input service name, eg: \r\ncd XxxService\r\ncd com.xxx.XxxService"; + } + StringBuilder buf = new StringBuilder(); + if (message.equals("/") || message.equals("..")) { + String service = (String) channel.getAttribute(SERVICE_KEY); + channel.removeAttribute(SERVICE_KEY); + buf.append("Cancelled default service " + service + "."); + } else { + boolean found = false; + for (Exporter exporter : DubboProtocol.getDubboProtocol().getExporters()) { + if (message.equals(exporter.getInvoker().getInterface().getSimpleName()) + || message.equals(exporter.getInvoker().getInterface().getName()) + || message.equals(exporter.getInvoker().getUrl().getPath())) { + found = true; + break; + } + } + if (found) { + channel.setAttribute(SERVICE_KEY, message); + buf.append("Used the " + message + " as default.\r\nYou can cancel default service by command: cd /"); + } else { + buf.append("No such service " + message); + } + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/CountTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/CountTelnetHandler.java new file mode 100644 index 0000000000..cc8b73e92d --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/CountTelnetHandler.java @@ -0,0 +1,166 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.remoting.telnet.support.TelnetUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcStatus; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * CountTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[service] [method] [times]", summary = "Count the service.", detail = "Count the service.") +@Extension("count") +public class CountTelnetHandler implements TelnetHandler { + + public String telnet(final Channel channel, String message) { + String service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY); + if ((service == null || service.length() == 0) + && (message == null || message.length() == 0)) { + return "Please input service name, eg: \r\ncount XxxService\r\ncount XxxService xxxMethod\r\ncount XxxService xxxMethod 10\r\nor \"cd XxxService\" firstly."; + } + StringBuilder buf = new StringBuilder(); + if (service != null && service.length() > 0) { + buf.append("Use default service " + service + ".\r\n"); + } + String[] parts = message.split("\\s+"); + String method; + String times; + if (service == null || service.length() == 0) { + service = parts.length > 0 ? parts[0] : null; + method = parts.length > 1 ? parts[1] : null; + } else { + method = parts.length > 0 ? parts[0] : null; + } + if (StringUtils.isInteger(method)) { + times = method; + method = null; + } else { + times = parts.length > 2 ? parts[2] : "1"; + } + if (! StringUtils.isInteger(times)) { + return "Illegal times " + times + ", must be integer."; + } + final int t = Integer.parseInt(times); + Invoker invoker = null; + for (Exporter exporter : DubboProtocol.getDubboProtocol().getExporters()) { + if (service.equals(exporter.getInvoker().getInterface().getSimpleName()) + || service.equals(exporter.getInvoker().getInterface().getName()) + || service.equals(exporter.getInvoker().getUrl().getPath())) { + invoker = exporter.getInvoker(); + break; + } + } + if (invoker != null) { + if (t > 0) { + final String mtd = method; + final Invoker inv = invoker; + final String prompt = channel.getUrl().getParameter("prompt", "telnet"); + Thread thread = new Thread(new Runnable() { + public void run() { + for (int i = 0; i < t; i ++) { + String result = count(inv, mtd); + try { + channel.send("\r\n" + result); + } catch (RemotingException e1) { + return; + } + if (i < t - 1) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + try { + channel.send("\r\n" + prompt + "> "); + } catch (RemotingException e1) { + return; + } + } + }, "TelnetCount"); + thread.setDaemon(true); + thread.start(); + } + } else { + buf.append("No such service " + service); + } + return buf.toString(); + } + + private String count(Invoker invoker, String method) { + URL url = invoker.getUrl(); + List> table = new ArrayList>(); + List header = new ArrayList(); + header.add("method"); + header.add("total"); + header.add("failed"); + header.add("active"); + header.add("average"); + header.add("max"); + if (method == null || method.length() == 0) { + for (Method m : invoker.getInterface().getMethods()) { + RpcStatus count = RpcStatus.getStatus(url, m.getName()); + List row = new ArrayList(); + row.add(m.getName()); + row.add(String.valueOf(count.getTotal())); + row.add(String.valueOf(count.getFailed())); + row.add(String.valueOf(count.getActive())); + row.add(String.valueOf(count.getSucceededAverageElapsed()) + "ms"); + row.add(String.valueOf(count.getSucceededMaxElapsed()) + "ms"); + table.add(row); + } + } else { + boolean found = false; + for (Method m : invoker.getInterface().getMethods()) { + if (m.getName().equals(method)) { + found = true; + break; + } + } + if (found) { + RpcStatus count = RpcStatus.getStatus(url, method); + List row = new ArrayList(); + row.add(method); + row.add(String.valueOf(count.getTotal())); + row.add(String.valueOf(count.getFailed())); + row.add(String.valueOf(count.getActive())); + row.add(String.valueOf(count.getSucceededAverageElapsed()) + "ms"); + row.add(String.valueOf(count.getSucceededMaxElapsed()) + "ms"); + table.add(row); + } else { + return "No such method " + method + " in class " + invoker.getInterface().getName(); + } + } + return TelnetUtils.toTable(header, table); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/CurrentTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/CurrentTelnetHandler.java new file mode 100644 index 0000000000..398bc50ed4 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/CurrentTelnetHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; + +/** + * CurrentServiceTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "", summary = "Print working default service.", detail = "Print working default service.") +@Extension("pwd") +public class CurrentTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + if (message.length() > 0) { + return "Unsupported parameter " + message + " for pwd."; + } + String service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY); + StringBuilder buf = new StringBuilder(); + if (service == null || service.length() == 0) { + buf.append("/"); + } else { + buf.append(service); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/InvokeTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/InvokeTelnetHandler.java new file mode 100644 index 0000000000..4c0f1f439d --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/InvokeTelnetHandler.java @@ -0,0 +1,126 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import java.lang.reflect.Method; +import java.util.List; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.dubbo.common.utils.PojoUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * InvokeTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[service.]method(args)", summary = "Invoke the service method.", detail = "Invoke the service method.") +@Extension("invoke") +public class InvokeTelnetHandler implements TelnetHandler { + + @SuppressWarnings("unchecked") + public String telnet(Channel channel, String message) { + if (message == null || message.length() == 0) { + return "Please input method name, eg: \r\ninvoke xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})\r\ninvoke XxxService.xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})\r\ninvoke com.xxx.XxxService.xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})"; + } + StringBuilder buf = new StringBuilder(); + String service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY); + if (service != null && service.length() > 0) { + buf.append("Use default service " + service + ".\r\n"); + } + int i = message.indexOf("("); + if (i < 0 || ! message.endsWith(")")) { + return "Invalid parameters, format: service.method(args)"; + } + String method = message.substring(0, i).trim(); + String args = message.substring(i + 1, message.length() - 1).trim(); + i = method.lastIndexOf("."); + if (i >= 0) { + service = method.substring(0, i).trim(); + method = method.substring(i + 1).trim(); + } + Invoker invoker = null; + Method invokeMethod = null; + for (Exporter exporter : DubboProtocol.getDubboProtocol().getExporters()) { + if (service == null || service.length() == 0) { + Method[] methods = exporter.getInvoker().getInterface().getMethods(); + for (Method m : methods) { + if (m.getName().equals(method) + || ReflectUtils.getSignature(m.getName(), m.getParameterTypes()).equals(method)) { + invoker = exporter.getInvoker(); + invokeMethod = m; + break; + } + } + if (invoker != null) { + break; + } + } else { + if (service.equals(exporter.getInvoker().getInterface().getSimpleName()) + || service.equals(exporter.getInvoker().getInterface().getName()) + || service.equals(exporter.getInvoker().getUrl().getPath())) { + invoker = exporter.getInvoker(); + Method[] methods = invoker.getInterface().getMethods(); + for (Method m : methods) { + if (m.getName().equals(method) + || ReflectUtils.getSignature(m.getName(), m.getParameterTypes()).equals(method)) { + invokeMethod = m; + } + } + break; + } + } + } + if (invoker != null) { + if (invokeMethod != null) { + List list; + try { + list = (List) JSON.parse("[" + args + "]", List.class); + } catch (Throwable t) { + return "Invalid json argument, cause: " + t.getMessage(); + } + try { + Object[] array = PojoUtils.realize(list.toArray(), invokeMethod.getParameterTypes()); + RpcContext.getContext().setLocalAddress(channel.getLocalAddress()).setRemoteAddress(channel.getRemoteAddress()); + long start = System.currentTimeMillis(); + Object result = invoker.invoke(new RpcInvocation(invokeMethod, array)).recreate(); + long end = System.currentTimeMillis(); + buf.append(JSON.json(result)); + buf.append("\r\nelapsed: "); + buf.append(end - start); + buf.append(" ms."); + } catch (Throwable t) { + return "Failed to invoke method " + invokeMethod.getName() + ", cause: " + t.getMessage(); + } + } else { + buf.append("No such method " + method + " in service " + service); + } + } else { + buf.append("No such service " + service); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/ListTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/ListTelnetHandler.java new file mode 100644 index 0000000000..bd8bae8607 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/ListTelnetHandler.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * ListTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[-l] [service]", summary = "List services and methods.", detail = "List services and methods.") +@Extension("ls") +public class ListTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + StringBuilder buf = new StringBuilder(); + String service = null; + boolean detail = false; + if (message.length() > 0) { + String[] parts = message.split("\\s+"); + for (String part : parts) { + if ("-l".equals(part)) { + detail = true; + } else { + if (service != null && service.length() > 0) { + return "Invaild parameter " + part; + } + service = part; + } + } + } else { + service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY); + if (service != null && service.length() > 0) { + buf.append("Use default service " + service + ".\r\n"); + } + } + if (service == null || service.length() == 0) { + for (Exporter exporter : DubboProtocol.getDubboProtocol().getExporters()) { + if (buf.length() > 0) { + buf.append("\r\n"); + } + buf.append(exporter.getInvoker().getInterface().getName()); + if (detail) { + buf.append(" -> "); + buf.append(exporter.getInvoker().getUrl()); + } + } + } else { + Invoker invoker = null; + for (Exporter exporter : DubboProtocol.getDubboProtocol().getExporters()) { + if (service.equals(exporter.getInvoker().getInterface().getSimpleName()) + || service.equals(exporter.getInvoker().getInterface().getName()) + || service.equals(exporter.getInvoker().getUrl().getPath())) { + invoker = exporter.getInvoker(); + break; + } + } + if (invoker != null) { + Method[] methods = invoker.getInterface().getMethods(); + for (Method method : methods) { + if (buf.length() > 0) { + buf.append("\r\n"); + } + if (detail) { + buf.append(ReflectUtils.getName(method)); + } else { + buf.append(method.getName()); + } + } + } else { + buf.append("No such service " + service); + } + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/LogTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/LogTelnetHandler.java new file mode 100644 index 0000000000..d9670a6e7e --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/LogTelnetHandler.java @@ -0,0 +1,94 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + + +import java.io.File; +import java.io.FileInputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Level; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; + +/** + * LogTelnetHandler + * @author chao.liuc + * + */ +@Help(parameter = "level", summary = "Change log level or show log ", detail = "Change log level or show log") +@Extension("log") +public class LogTelnetHandler implements TelnetHandler { + + public static final String SERVICE_KEY = "telnet.log"; + + public String telnet(Channel channel, String message) { + long size = 0 ; + File file = LoggerFactory.getFile(); + StringBuffer buf = new StringBuffer(); + if (message == null || message.trim().length() == 0) { + buf.append("EXAMPLE: log error / log 100"); + }else { + String str[] = message.split(" "); + if (! StringUtils.isInteger(str[0])){ + LoggerFactory.setLevel(Level.valueOf(message.toUpperCase())); + } else { + int SHOW_LOG_LENGTH = Integer.parseInt(str[0]); + + if (file != null && file.exists()) { + try{ + FileInputStream fis = new FileInputStream(file); + FileChannel filechannel = fis.getChannel(); + size = filechannel.size(); + ByteBuffer bb; + if (size <= SHOW_LOG_LENGTH) { + bb = ByteBuffer.allocate((int) size); + filechannel.read(bb, 0); + } else { + int pos = (int) (size - SHOW_LOG_LENGTH); + bb = ByteBuffer.allocate(SHOW_LOG_LENGTH); + filechannel.read(bb, pos); + } + bb.flip(); + String content = new String(bb.array()).replace("<", "<") + .replace(">", ">").replace("\n", "

    "); + buf.append("\r\ncontent:"+content); + + buf.append("\r\nmodified:"+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + .format(new Date(file.lastModified())))); + buf.append("\r\nsize:"+size +"\r\n"); + }catch (Exception e) { + buf.append(e.getMessage()); + } + }else { + size = 0; + buf.append("\r\nMESSAGE: log file not exists or log appender is console ."); + } + } + } + buf.append("\r\nCURRENT LOG LEVEL:"+ LoggerFactory.getLevel()) + .append("\r\nCURRENT LOG APPENDER:"+ (file == null ? "console" : file.getAbsolutePath())); + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/PortTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/PortTelnetHandler.java new file mode 100644 index 0000000000..d5ada09462 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/PortTelnetHandler.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import java.util.Collection; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; + +/** + * ServerTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[-l] [port]", summary = "Print server ports and connections.", detail = "Print server ports and connections.") +@Extension("ps") +public class PortTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + StringBuilder buf = new StringBuilder(); + String port = null; + boolean detail = false; + if (message.length() > 0) { + String[] parts = message.split("\\s+"); + for (String part : parts) { + if ("-l".equals(part)) { + detail = true; + } else { + if (port != null && port.length() > 0) { + return "Invaild parameter " + part; + } + port = part; + } + } + } + if (port == null || port.length() == 0) { + for (ExchangeServer server : DubboProtocol.getDubboProtocol().getServers()) { + if (buf.length() > 0) { + buf.append("\r\n"); + } + if (detail) { + buf.append(server.getUrl().getProtocol() + "://" + server.getUrl().getAddress()); + } else { + buf.append(server.getUrl().getPort()); + } + } + } else { + if (! StringUtils.isInteger(port)) { + return "Illegal port " + port + ", must be integer."; + } + int p = Integer.parseInt(port); + ExchangeServer server = null; + for (ExchangeServer s : DubboProtocol.getDubboProtocol().getServers()) { + if (p == s.getUrl().getPort()) { + server = s; + break; + } + } + if (server != null) { + Collection channels = server.getExchangeChannels(); + for (ExchangeChannel c : channels) { + if (buf.length() > 0) { + buf.append("\r\n"); + } + if (detail) { + buf.append(c.getRemoteAddress() + " -> " + c.getLocalAddress()); + } else { + buf.append(c.getRemoteAddress()); + } + } + } else { + buf.append("No such port " + port); + } + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/TraceTelnetHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/TraceTelnetHandler.java new file mode 100644 index 0000000000..46155c71b7 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/dubbo/telnet/TraceTelnetHandler.java @@ -0,0 +1,96 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo.telnet; + +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import com.alibaba.dubbo.remoting.telnet.support.Help; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.dubbo.DubboProtocol; +import com.alibaba.dubbo.rpc.filter.TraceFilter; + +/** + * TraceTelnetHandler + * + * @author william.liangf + */ +@Help(parameter = "[service] [method] [times]", summary = "Trace the service.", detail = "Trace the service.") +@Extension("trace") +public class TraceTelnetHandler implements TelnetHandler { + + public String telnet(Channel channel, String message) { + String service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY); + if ((service == null || service.length() == 0) + && (message == null || message.length() == 0)) { + return "Please input service name, eg: \r\ntrace XxxService\r\ntrace XxxService xxxMethod\r\ntrace XxxService xxxMethod 10\r\nor \"cd XxxService\" firstly."; + } + StringBuilder buf = new StringBuilder(); + if (service != null && service.length() > 0) { + buf.append("Use default service " + service + ".\r\n"); + } + String[] parts = message.split("\\s+"); + String method; + String times; + if (service == null || service.length() == 0) { + service = parts.length > 0 ? parts[0] : null; + method = parts.length > 1 ? parts[1] : null; + } else { + method = parts.length > 0 ? parts[0] : null; + } + if (StringUtils.isInteger(method)) { + times = method; + method = null; + } else { + times = parts.length > 2 ? parts[2] : "1"; + } + if (! StringUtils.isInteger(times)) { + return "Illegal times " + times + ", must be integer."; + } + Invoker invoker = null; + for (Exporter exporter : DubboProtocol.getDubboProtocol().getExporters()) { + if (service.equals(exporter.getInvoker().getInterface().getSimpleName()) + || service.equals(exporter.getInvoker().getInterface().getName()) + || service.equals(exporter.getInvoker().getUrl().getPath())) { + invoker = exporter.getInvoker(); + break; + } + } + if (invoker != null) { + if (method != null && method.length() > 0) { + boolean found = false; + for (Method m : invoker.getInterface().getMethods()) { + if (m.getName().equals(method)) { + found = true; + break; + } + } + if (! found) { + return "No such method " + method + " in class " + invoker.getInterface().getName(); + } + } + TraceFilter.addTracer(invoker.getInterface(), method, channel, Integer.parseInt(times)); + } else { + buf.append("No such service " + service); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java new file mode 100644 index 0000000000..04495eee69 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/AccessLogFilter.java @@ -0,0 +1,202 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.io.File; +import java.io.FileWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * 记录Service的Access Log。 + *

    + * 使用的Logger key是DUBBO.ACCESS-LOG。 + * 如果要配置Access Log只出现在指定的Appender中,在Log4j中注意配置上additivity。配置示例: + * + *

    + * <logger name="DUBBO.ACCESS-LOG" additivity="false">
    + *    <level value="info" />
    + *    <appender-ref ref="foo" />
    + * </logger>
    + * 
    + * + * @author ding.lid + */ +@Extension("accesslog") +public class AccessLogFilter implements Filter { + + private static final Logger logger = LoggerFactory.getLogger(AccessLogFilter.class); + + private static final String ACCESS_LOG_KEY = "dubbo.accesslog"; + + private static final String FILE_DATE_FORMAT = "yyyyMMdd"; + + private static final String MESSAGE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + private static final int LOG_MAX_BUFFER = 5000; + + private static final long LOG_OUTPUT_INTERVAL = 5000; + + private final ConcurrentMap> logQueue = new ConcurrentHashMap>(); + + private final ScheduledExecutorService logScheduled = Executors.newScheduledThreadPool(2, new NamedThreadFactory("Dubbo-Access-Log", true)); + + private volatile ScheduledFuture logFuture = null; + + private class LogTask implements Runnable { + public void run() { + try { + if (logQueue != null && logQueue.size() > 0) { + for (Map.Entry> entry : logQueue.entrySet()) { + try { + String accesslog = entry.getKey(); + Set logSet = entry.getValue(); + File file = new File(accesslog); + File dir = file.getParentFile(); + if (! dir.exists()) { + dir.mkdirs(); + } + if (logger.isDebugEnabled()) { + logger.debug("Append log to " + accesslog); + } + if (file.exists()) { + String now = new SimpleDateFormat(FILE_DATE_FORMAT).format(new Date()); + String last = new SimpleDateFormat(FILE_DATE_FORMAT).format(new Date(file.lastModified())); + if (! now.equals(last)) { + File archive = new File(file.getAbsolutePath() + "." + last); + file.renameTo(archive); + } + } + FileWriter writer = new FileWriter(file, true); + try { + for (String msg : logSet) { + writer.write(msg); + writer.write("\r\n"); + } + writer.flush(); + } finally { + writer.close(); + } + logSet.clear(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + + private void init() { + if (logFuture == null) { + synchronized (logScheduled) { + if (logFuture == null) { + logFuture = logScheduled.scheduleWithFixedDelay(new LogTask(), LOG_OUTPUT_INTERVAL, LOG_OUTPUT_INTERVAL, TimeUnit.MILLISECONDS); + } + } + } + } + + private void log(String accesslog, String logmessage) { + init(); + Set logSet = logQueue.get(accesslog); + if (logSet == null) { + logQueue.putIfAbsent(accesslog, new ConcurrentHashSet()); + logSet = logQueue.get(accesslog); + } + if (logSet.size() < LOG_MAX_BUFFER) { + logSet.add(logmessage); + } + } + + public Result invoke(Invoker invoker, Invocation inv) throws RpcException { + try { + String accesslog = invoker.getUrl().getParameter(Constants.ACCESS_LOG_KEY); + if (ConfigUtils.isNotEmpty(accesslog)) { + RpcContext context = RpcContext.getContext(); + String serviceName = invoker.getInterface().getName(); + String version = invoker.getUrl().getParameter(Constants.VERSION_KEY); + String group = invoker.getUrl().getParameter(Constants.GROUP_KEY); + StringBuilder sn = new StringBuilder(); + sn.append("[").append(new SimpleDateFormat(MESSAGE_DATE_FORMAT).format(new Date())).append("] ").append(context.getRemoteHost()).append(":").append(context.getRemotePort()) + .append(" -> ").append(context.getLocalHost()).append(":").append(context.getLocalPort()) + .append(" - "); + if (null != group && group.length() > 0) { + sn.append(group).append("/"); + } + sn.append(serviceName); + if (null != version && version.length() > 0) { + sn.append(":").append(version); + } + sn.append(" "); + sn.append(inv.getMethodName()); + sn.append("("); + Class[] types = inv.getParameterTypes(); + if (types != null && types.length > 0) { + boolean first = true; + for (Class type : types) { + if (first) { + first = false; + } else { + sn.append(","); + } + sn.append(type.getName()); + } + } + sn.append(") "); + Object[] args = inv.getArguments(); + if (args != null && args.length > 0) { + sn.append(JSON.json(args)); + } + String msg = sn.toString(); + if (ConfigUtils.isDefault(accesslog)) { + LoggerFactory.getLogger(ACCESS_LOG_KEY + "." + invoker.getInterface().getName()).info(msg); + } else { + log(accesslog, msg); + } + } + } catch (Throwable t) { + logger.warn("Exception in AcessLogFilter of service(" + invoker + " -> " + inv + ")", t); + } + return invoker.invoke(inv); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilter.java new file mode 100644 index 0000000000..298cdd2166 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilter.java @@ -0,0 +1,87 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcStatus; + +/** + * LimitInvokerFilter + * + * @author william.liangf + */ +@Extension("activelimit") +public class ActiveLimitFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + URL url = invoker.getUrl(); + String methodName = invocation.getMethodName(); + int max = invoker.getUrl().getMethodIntParameter(methodName, Constants.ACTIVES_KEY); + RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()); + if (max > 0) { + long timeout = invoker.getUrl().getMethodIntParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY); + long start = System.currentTimeMillis(); + long remain = timeout; + int active = count.getActive(); + if (active >= max) { + synchronized (count) { + active = count.getActive(); + while (active >= max) { + try { + count.wait(remain); + } catch (InterruptedException e) { + } + long elapsed = System.currentTimeMillis() - start; + remain = timeout - elapsed; + if (remain <= 0) { + throw new RpcException("Waiting concurrent invoke timeout in client-side for service: " + + invoker.getInterface().getName() + ", method: " + + invocation.getMethodName() + ", elapsed: " + elapsed + + ", timeout: " + timeout + ". concurrent invokes: " + active + + ". max concurrent invoke limit: " + max); + } + } + } + } + } + try { + long begin = System.currentTimeMillis(); + RpcStatus.beginCount(url, methodName); + try { + Result result = invoker.invoke(invocation); + RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, true); + return result; + } catch (RuntimeException t) { + RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, false); + throw t; + } + } finally { + if(max>0){ + synchronized (count) { + count.notify(); + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ClassLoaderFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ClassLoaderFilter.java new file mode 100644 index 0000000000..f5b9a90033 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ClassLoaderFilter.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * ClassLoaderInvokerFilter + * + * @author william.liangf + */ +@Extension("classloader") +public class ClassLoaderFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + ClassLoader ocl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(invoker.getInterface().getClassLoader()); + try { + return invoker.invoke(invocation); + } finally { + Thread.currentThread().setContextClassLoader(ocl); + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/CompatibleFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/CompatibleFilter.java new file mode 100644 index 0000000000..278591ff99 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/CompatibleFilter.java @@ -0,0 +1,77 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.CompatibleTypeUtils; +import com.alibaba.dubbo.common.utils.PojoUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * CompatibleFilter + * + * @author william.liangf + */ +@Extension("compatible") +public class CompatibleFilter implements Filter { + + private static Logger logger = LoggerFactory.getLogger(CompatibleFilter.class); + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Result result = invoker.invoke(invocation); + if (! invocation.getMethodName().startsWith("$") && ! result.hasException()) { + Object value = result.getResult(); + if (value != null) { + try { + Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes()); + Class type = method.getReturnType(); + Object newValue; + String serialization = invoker.getUrl().getParameter(Constants.SERIALIZATION_KEY); + if ("json".equals(serialization) + || "fastjson".equals(serialization)){ + Type gtype = method.getGenericReturnType(); + newValue = PojoUtils.realize(value, type, gtype); + } else if (! type.isInstance(value)) { + newValue = PojoUtils.isPojo(type) + ? PojoUtils.realize(value, type) + : CompatibleTypeUtils.compatibleTypeConvert(value, type); + + } else { + newValue = value; + } + if (newValue != value) { + result = new RpcResult(newValue); + } + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + return result; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java new file mode 100644 index 0000000000..3e337d39f8 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * ConsumerContextInvokerFilter + * + * @author william.liangf + */ +@Extension("consumercontext") +public class ConsumerContextFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + RpcContext.getContext() + .setInvoker(invoker) + .setInvocation(invocation) + .setLocalAddress(NetUtils.getLocalHost(), 0) + .setRemoteAddress(invoker.getUrl().getHost(), + invoker.getUrl().getPort()); + return invoker.invoke(invocation); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java new file mode 100644 index 0000000000..734a3a634b --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * ContextInvokerFilter + * + * @author william.liangf + */ +@Extension("context") +public class ContextFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Map attachments = invocation.getAttachments(); + if (attachments != null) { + attachments = new HashMap(attachments); + attachments.remove(Constants.PATH_KEY); + attachments.remove(Constants.GROUP_KEY); + attachments.remove(Constants.VERSION_KEY); + attachments.remove(Constants.DUBBO_VERSION_KEY); + attachments.remove(Constants.TOKEN_KEY); + attachments.remove(Constants.TIMEOUT_KEY); + } + RpcContext.getContext() + .setInvoker(invoker) + .setInvocation(invocation) + .setAttachments(attachments) + .setLocalAddress(invoker.getUrl().getHost(), + invoker.getUrl().getPort()); + try { + return invoker.invoke(invocation); + } finally { + RpcContext.removeContext(); + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/DeprecatedFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/DeprecatedFilter.java new file mode 100644 index 0000000000..131a677c49 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/DeprecatedFilter.java @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.util.Set; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * DeprecatedInvokerFilter + * + * @author william.liangf + */ +@Extension("deprecated") +public class DeprecatedFilter implements Filter { + + private static final Logger LOGGER = LoggerFactory.getLogger(DeprecatedFilter.class); + + private static final Set logged = new ConcurrentHashSet(); + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + String key = invoker.getInterface().getName() + "." + invocation.getMethodName(); + if (! logged.contains(key)) { + logged.add(key); + if (invoker.getUrl().getMethodBooleanParameter(invocation.getMethodName(), Constants.DEPRECATED_KEY)) { + LOGGER.error("The service method " + invoker.getInterface().getName() + "." + getMethodSignature(invocation) + " is DEPRECATED! Declare from " + invoker.getUrl()); + } + } + return invoker.invoke(invocation); + } + + private String getMethodSignature(Invocation invocation) { + StringBuilder buf = new StringBuilder(invocation.getMethodName()); + buf.append("("); + Class[] types = invocation.getParameterTypes(); + if (types != null && types.length > 0) { + boolean first = true; + for (Class type : types) { + if (first) { + first = false; + } else { + buf.append(", "); + } + buf.append(type.getSimpleName()); + } + } + buf.append(")"); + return buf.toString(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java new file mode 100644 index 0000000000..83fb1a1981 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * EchoInvokerFilter + * + * @author william.liangf + */ +@Extension("echo") +public class EchoFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation inv) throws RpcException { + if(inv.getMethodName().equals(Constants.$ECHO) && inv.getArguments() != null && inv.getArguments().length == 1 ) + return new RpcResult(inv.getArguments()[0]); + return invoker.invoke(inv); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/EventFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/EventFilter.java new file mode 100644 index 0000000000..8ce4f581d8 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/EventFilter.java @@ -0,0 +1,194 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.Future; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.exchange.ResponseCallback; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.StaticContext; +import com.alibaba.dubbo.rpc.support.FutureAdapter; + +/** + * EventFilter + * @author chao.liuc + * @author william.liangf + */ +@Extension("event") +public class EventFilter implements Filter { + + protected static final Logger logger = LoggerFactory.getLogger(EventFilter.class); + + public Result invoke(final Invoker invoker, final Invocation invocation) throws RpcException { + fireInvokeCallback(invoker, invocation); + //需要在调用前配置好是否有返回值,已供invoker判断是否需要返回future. + Result result = invoker.invoke(invocation); + if (invoker.getUrl().getMethodBooleanParameter(invocation.getMethodName(), Constants.ASYNC_KEY)) { + asyncCallback(invoker, invocation); + } else { + syncCallback(invoker, invocation, result); + } + return result; + } + + private void syncCallback(final Invoker invoker, final Invocation invocation, final Result result) { + if (result.hasException()) { + fireThrowCallback(invoker, invocation, result.getException()); + } else { + fireReturnCallback(invoker, invocation, result.getResult()); + } + } + + private void asyncCallback(final Invoker invoker, final Invocation invocation) { + Future f = RpcContext.getContext().getFuture(); + if (f instanceof FutureAdapter) { + ResponseFuture future = ((FutureAdapter)f).getFuture(); + future.setCallback(new ResponseCallback() { + public void done(Object response) { + Result result = (Result) response; + if (result.hasException()) { + fireThrowCallback(invoker, invocation, result.getException()); + } else { + fireReturnCallback(invoker, invocation, result.getResult()); + } + } + public void caught(Throwable exception) { + fireThrowCallback(invoker, invocation, exception); + } + }); + } + } + + private void fireInvokeCallback(final Invoker invoker, final Invocation invocation) { + final Method onInvokeMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), RpcConstants.ON_INVOKE_METHOD_KEY)); + final Object onInvokeInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), RpcConstants.ON_INVOKE_INSTANCE_KEY)); + + if (onInvokeMethod == null && onInvokeInst == null ){ + return ; + } + if (onInvokeMethod == null || onInvokeInst == null ){ + throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() +" has a onreturn callback config , but no such "+(onInvokeMethod == null ? "method" : "instance")+" found. url:"+invoker.getUrl()); + } + if (onInvokeMethod != null && ! onInvokeMethod.isAccessible()) { + onInvokeMethod.setAccessible(true); + } + + Object[] params = invocation.getArguments(); + try { + onInvokeMethod.invoke(onInvokeInst, params); + } catch (InvocationTargetException e) { + fireThrowCallback(invoker, invocation, e.getTargetException()); + } catch (Throwable e) { + fireThrowCallback(invoker, invocation, e); + } + } + + private void fireReturnCallback(final Invoker invoker, final Invocation invocation, final Object result) { + final Method onReturnMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), RpcConstants.ON_RETURN_METHOD_KEY)); + final Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), RpcConstants.ON_RETURN_INSTANCE_KEY)); + + //not set onreturn callback + if (onReturnMethod == null && onReturnInst == null ){ + return ; + } + + if (onReturnMethod == null || onReturnInst == null ){ + throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() +" has a onreturn callback config , but no such "+(onReturnMethod == null ? "method" : "instance")+" found. url:"+invoker.getUrl()); + } + if (onReturnMethod != null && ! onReturnMethod.isAccessible()) { + onReturnMethod.setAccessible(true); + } + + Object[] args = invocation.getArguments(); + Object[] params ; + Class[] rParaTypes = onReturnMethod.getParameterTypes() ; + if (rParaTypes.length >1 ) { + if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)){ + params = new Object[2]; + params[0] = result; + params[1] = args ; + }else { + params = new Object[args.length + 1]; + params[0] = result; + System.arraycopy(args, 0, params, 1, args.length); + } + } else { + params = new Object[] { result }; + } + try { + onReturnMethod.invoke(onReturnInst, params); + } catch (InvocationTargetException e) { + fireThrowCallback(invoker, invocation, e.getTargetException()); + } catch (Throwable e) { + fireThrowCallback(invoker, invocation, e); + } + } + + private void fireThrowCallback(final Invoker invoker, final Invocation invocation, final Throwable exception) { + final Method onthrowMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), RpcConstants.ON_THROW_METHOD_KEY)); + final Object onthrowInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), RpcConstants.ON_THROW_INSTANCE_KEY)); + + //没有设置onthrow callback. + if (onthrowMethod == null && onthrowInst == null ){ + return ; + } + if (onthrowMethod == null || onthrowInst == null ){ + throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() +" has a onthrow callback config , but no such "+(onthrowMethod == null ? "method" : "instance")+" found. url:"+invoker.getUrl()); + } + if (onthrowMethod != null && ! onthrowMethod.isAccessible()) { + onthrowMethod.setAccessible(true); + } + Class[] rParaTypes = onthrowMethod.getParameterTypes() ; + if (rParaTypes[0].isAssignableFrom(exception.getClass())){ + try { + Object[] args = invocation.getArguments(); + Object[] params; + + if (rParaTypes.length >1 ) { + if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)){ + params = new Object[2]; + params[0] = exception; + params[1] = args ; + }else { + params = new Object[args.length + 1]; + params[0] = exception; + System.arraycopy(args, 0, params, 1, args.length); + } + } else { + params = new Object[] { exception }; + } + onthrowMethod.invoke(onthrowInst,params); + } catch (Throwable e) { + logger.error(invocation.getMethodName() +".call back method invoke error . callback method :" + onthrowMethod + ", url:"+ invoker.getUrl(), e); + } + } else { + logger.error(invocation.getMethodName() +".call back method invoke error . callback method :" + onthrowMethod + ", url:"+ invoker.getUrl(), exception); + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java new file mode 100644 index 0000000000..3a58d33ddd --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * ExceptionInvokerFilter + * + * @author william.liangf + */ +@Extension("exception") +public class ExceptionFilter implements Filter { + + private static final Logger logger = LoggerFactory.getLogger(ExceptionFilter.class); + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Result result = invoker.invoke(invocation); + if (result.hasException() && GenericService.class != invoker.getInterface()) { + try { + Throwable exception = result.getException(); + try { + Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes()); + Class[] exceptionClassses = method.getExceptionTypes(); + for (Class exceptionClass : exceptionClassses) { + if (exception.getClass().equals(exceptionClass)) { + return result; + } + } + } catch (NoSuchMethodException e) { + return result; + } + //在package里有类,直接抛出 + String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface()); + String exceptionFile = ReflectUtils.getCodeBase(exception.getClass()); + if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){ + return result; + } + //除上面二种情况外,server端打印日志,并包装成runtimeException抛给客户端 + logger.error("Got unchecked and undeclare service method invoke exception: " + exception.getMessage(), exception); + return new RpcResult(new RuntimeException(StringUtils.toString(exception))); + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + return result; + } + } + return result; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ExecuteLimitFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ExecuteLimitFilter.java new file mode 100644 index 0000000000..e1c3501391 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ExecuteLimitFilter.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcStatus; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * ThreadLimitInvokerFilter + * + * @author william.liangf + */ +@Extension("executelimit") +public class ExecuteLimitFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + URL url = invoker.getUrl(); + String methodName = invocation.getMethodName(); + int max = url.getMethodIntParameter(methodName, Constants.EXECUTES_KEY); + if (max > 0) { + RpcStatus count = RpcStatus.getStatus(url, invocation.getMethodName()); + if (count.getActive() >= max) { + throw new RpcException("Failed to invoke invocation " + invocation + " in provider " + url + ", cause: The service using threads greater than limited."); + } + } + long begin = System.currentTimeMillis(); + RpcStatus.beginCount(url, methodName); + try { + Result result = invoker.invoke(invocation); + RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, true); + return result; + } catch (RuntimeException t) { + RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, false); + throw t; + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java new file mode 100644 index 0000000000..ba71fffb7f --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.lang.reflect.Method; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.PojoUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.service.GenericException; + +/** + * GenericInvokerFilter. + * + * @author william.liangf + */ +@Extension("generic") +public class GenericFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation inv) throws RpcException { + if (inv.getMethodName().equals(Constants.$INVOKE) + && inv.getArguments() != null + && inv.getArguments().length == 3 + && ! invoker.getUrl().getBooleanParameter(Constants.GENERIC_KEY)) { + String name = ((String) inv.getArguments()[0]).trim(); + String[] types = (String[]) inv.getArguments()[1]; + Object[] args = (Object[]) inv.getArguments()[2]; + try { + Method method = ReflectUtils.findMethodByMethodSignature(invoker.getInterface(), name, types); + Class[] params = method.getParameterTypes(); + if (args == null) { + args = new Object[params.length]; + } + args = PojoUtils.realize(args, params); + Result result = invoker.invoke(new RpcInvocation(method, args)); + if (result.hasException()) { + return new RpcResult(new GenericException(result.getException())); + } + return new RpcResult(PojoUtils.generalize(result.getResult())); + } catch (NoSuchMethodException e) { + throw new RpcException(e.getMessage(), e); + } catch (ClassNotFoundException e) { + throw new RpcException(e.getMessage(), e); + } + } + return invoker.invoke(inv); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java new file mode 100644 index 0000000000..b62eb004ec --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.PojoUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * GenericImplInvokerFilter + * + * @author william.liangf + */ +@Extension("genericimpl") +public class GenericImplFilter implements Filter { + + private static final Class[] GENERIC_PARAMETER_TYPES = new Class[] {String.class, String[].class, Object[].class}; + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + if (invoker.getUrl().getBooleanParameter(Constants.GENERIC_KEY) + && ! Constants.$INVOKE.equals(invocation.getMethodName()) + && invocation instanceof RpcInvocation) { + RpcInvocation invocation2 = (RpcInvocation) invocation; + String methodName = invocation2.getMethodName(); + Class[] parameterTypes = invocation2.getParameterTypes(); + Object[] arguments = invocation2.getArguments(); + + String[] types = new String[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i ++) { + types[i] = ReflectUtils.getName(parameterTypes[i]); + } + Object[] args = PojoUtils.generalize(arguments); + + invocation2.setMethodName(Constants.$INVOKE); + invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES); + invocation2.setArguments(new Object[] {methodName, types, args}); + Result result = invoker.invoke(invocation2); + + if (! result.hasException()) { + Object value = result.getResult(); + try { + return new RpcResult(PojoUtils.realize(value, invoker.getInterface().getMethod(methodName, parameterTypes).getReturnType())); + } catch (NoSuchMethodException e) { + throw new RpcException(e.getMessage(), e); + } + } + return result; + } + return invoker.invoke(invocation); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ReadyFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ReadyFilter.java new file mode 100644 index 0000000000..cf5363c015 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/ReadyFilter.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcStatus; + +/** + * ReadyFilter + * + * @author william.liangf + */ +@Extension("ready") +public class ReadyFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + if (! RpcStatus.getStatus(invoker.getUrl()).isReady()) { + throw new RpcException("The service not ready! Limit by config , service: " + invoker.getInterface().getName() + ", url: " + invoker.getUrl()); + } + if (! RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).isReady()) { + throw new RpcException("The service method not ready! Limit by config , service: " + invoker.getInterface().getName() + ", url: " + invoker.getUrl() + ", method: " + invocation.getMethodName()); + } + return invoker.invoke(invocation); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TimeoutFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TimeoutFilter.java new file mode 100644 index 0000000000..b38ff3a4ab --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TimeoutFilter.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * 如果执行timeout,则log记录下,不干涉服务的运行 + * + * @author chao.liuc + */ +@Extension("timeout") +public class TimeoutFilter implements Filter { + private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class); + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + long start = System.currentTimeMillis(); + Result result = invoker.invoke(invocation); + long elapsed = System.currentTimeMillis() - start; + if (invoker.getUrl() != null + && elapsed > invoker.getUrl().getMethodIntParameter(invocation.getMethodName(), "timeout", Integer.MAX_VALUE) ){ + if(logger.isWarnEnabled()){ + logger.warn("invoke time out. method: " + invocation.getMethodName() + "arguments: "+invocation.getArguments()+" , url is "+invoker.getUrl() + ", invoke elapsed "+elapsed+" ms."); + } + } + return result; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TokenFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TokenFilter.java new file mode 100644 index 0000000000..6d2008cbb3 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TokenFilter.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * TokenInvokerFilter + * + * @author william.liangf + */ +@Extension("token") +public class TokenFilter implements Filter { + + public Result invoke(Invoker invoker, Invocation inv) + throws RpcException { + String token = invoker.getUrl().getParameter(Constants.TOKEN_KEY); + if (ConfigUtils.isNotEmpty(token)) { + Class serviceType = invoker.getInterface(); + Map attachments = inv.getAttachments(); + String remoteToken = attachments == null ? null : attachments.get(Constants.TOKEN_KEY); + if (! token.equals(remoteToken)) { + throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost()); + } + } + return invoker.invoke(inv); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TraceFilter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TraceFilter.java new file mode 100644 index 0000000000..63b82876cf --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/filter/TraceFilter.java @@ -0,0 +1,124 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import java.util.ArrayList; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.json.JSON; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.remoting.Channel; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * TraceFilter + * + * @author william.liangf + */ +@Extension("trace") +public class TraceFilter implements Filter { + + private static final Logger logger = LoggerFactory.getLogger(TraceFilter.class); + + private static final String TRACE_MAX = "trace.max"; + + private static final String TRACE_COUNT = "trace.count"; + + private static final ConcurrentMap> tracers = new ConcurrentHashMap>(); + + public static void addTracer(Class type, String method, Channel channel, int max) { + channel.setAttribute(TRACE_MAX, max); + channel.setAttribute(TRACE_COUNT, new AtomicInteger()); + String key = method != null && method.length() > 0 ? type.getName() + "." + method : type.getName(); + Set channels = tracers.get(key); + if (channels == null) { + tracers.putIfAbsent(key, new ConcurrentHashSet()); + channels = tracers.get(key); + } + channels.add(channel); + } + + public static void removeTracer(Class type, String method, Channel channel) { + channel.removeAttribute(TRACE_MAX); + channel.removeAttribute(TRACE_COUNT); + String key = method != null && method.length() > 0 ? type.getName() + "." + method : type.getName(); + Set channels = tracers.get(key); + if (channels != null) { + channels.remove(channel); + } + } + + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + long start = System.currentTimeMillis(); + Result result = invoker.invoke(invocation); + long end = System.currentTimeMillis(); + if (tracers.size() > 0) { + String key = invoker.getInterface().getName() + "." + invocation.getMethodName(); + Set channels = tracers.get(key); + if (channels == null || channels.size() == 0) { + key = invoker.getInterface().getName(); + channels = tracers.get(key); + } + if (channels != null && channels.size() > 0) { + for (Channel channel : new ArrayList(channels)) { + if (channel.isConnected()) { + try { + int max = 1; + Integer m = (Integer) channel.getAttribute(TRACE_MAX); + if (m != null) { + max = (int) m; + } + int count = 0; + AtomicInteger c = (AtomicInteger) channel.getAttribute(TRACE_COUNT); + if (c == null) { + c = new AtomicInteger(); + channel.setAttribute(TRACE_COUNT, c); + } + count = c.getAndIncrement(); + if (count < max) { + String prompt = channel.getUrl().getParameter("prompt", "telnet"); + channel.send("\r\n" + RpcContext.getContext().getRemoteAddress() + " -> " + + invoker.getInterface().getName() + + "." + invocation.getMethodName() + + "(" + JSON.json(invocation.getArguments()) + ")" + " -> " + JSON.json(result.getResult()) + + "\r\nelapsed: "+(end - start) +" ms." + + "\r\n\r\n" + prompt + "> "); + } + } catch (Throwable e) { + channels.remove(channel); + logger.warn(e.getMessage(), e); + } + } else { + channels.remove(channel); + } + } + } + } + return result; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmExporter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmExporter.java new file mode 100644 index 0000000000..e7183d3fab --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmExporter.java @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.injvm; + +import java.util.Map; + +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.support.AbstractExporter; + +/** + * InjvmExporter + * + * @author william.liangf + */ +class InjvmExporter extends AbstractExporter { + + private final String key; + + private final Map> exporterMap; + + InjvmExporter(Invoker invoker, String key, Map> exporterMap){ + super(invoker); + this.key = key; + this.exporterMap = exporterMap; + exporterMap.put(key, this); + } + + public void unexport() { + super.unexport(); + exporterMap.remove(key); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmInvoker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmInvoker.java new file mode 100644 index 0000000000..3766afc29c --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmInvoker.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.injvm; + +import java.util.Map; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.support.AbstractInvoker; + +/** + * InjvmInvoker + * + * @author william.liangf + */ +class InjvmInvoker extends AbstractInvoker { + + private final String key; + + private final Map> exporterMap; + + InjvmInvoker(Class type, URL url, String key, Map> exporterMap){ + super(type, url); + this.key = key; + this.exporterMap = exporterMap; + } + + public Object doInvoke(Invocation invocation) throws Throwable { + InjvmExporter exporter = (InjvmExporter) exporterMap.get(key); + if (exporter == null) { + throw new RpcException("Service [" + key + "] not found."); + } + Result result; + try { + result = exporter.invoke(invocation, NetUtils.LOCALHOST, 0); + } catch (RpcException e) { + throw e; + } catch (Throwable e) { + throw new RpcException(e); + } + return result.recreate(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmProtocol.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmProtocol.java new file mode 100644 index 0000000000..3f79117e13 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/injvm/InjvmProtocol.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.injvm; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.support.AbstractProtocol; + +/** + * InjvmProtocol + * + * @author qian.lei + * @author william.liangf + */ +@Extension(InjvmProtocol.NAME) +public class InjvmProtocol extends AbstractProtocol implements Protocol { + + public static final String NAME = "injvm"; + + public static final int DEFAULT_PORT = 1; + + public int getDefaultPort() { + return DEFAULT_PORT; + } + + public Exporter export(Invoker invoker) throws RpcException { + return new InjvmExporter(invoker, serviceKey(invoker.getUrl()), exporterMap); + } + + public Invoker refer(Class serviceType, URL url) throws RpcException { + return new InjvmInvoker(serviceType, url, serviceKey(url), exporterMap); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/DeprecatedInvokerListener.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/DeprecatedInvokerListener.java new file mode 100644 index 0000000000..ecc729a0e5 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/DeprecatedInvokerListener.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.listener; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * DeprecatedProtocolFilter + * + * @author william.liangf + */ +@Extension("deprecated") +public class DeprecatedInvokerListener extends InvokerListenerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(DeprecatedInvokerListener.class); + + public void referred(Invoker invoker) throws RpcException { + if (invoker.getUrl().getBooleanParameter(Constants.DEPRECATED_KEY)) { + LOGGER.error("The service " + invoker.getInterface().getName() + " is DEPRECATED! Declare from " + invoker.getUrl()); + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ExporterListenerAdapter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ExporterListenerAdapter.java new file mode 100644 index 0000000000..1859ac185f --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ExporterListenerAdapter.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.listener; + +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.ExporterListener; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * ExporterListenerAdapter + * + * @author william.liangf + */ +public abstract class ExporterListenerAdapter implements ExporterListener { + + public void exported(Exporter exporter) throws RpcException { + } + + public void unexported(Exporter exporter) throws RpcException { + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/InvokerListenerAdapter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/InvokerListenerAdapter.java new file mode 100644 index 0000000000..57cfc3cfab --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/InvokerListenerAdapter.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.listener; + +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.InvokerListener; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * InvokerListenerAdapter + * + * @author william.liangf + */ +public abstract class InvokerListenerAdapter implements InvokerListener { + + public void referred(Invoker invoker) throws RpcException { + } + + public void destroyed(Invoker invoker) { + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerExporterWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerExporterWrapper.java new file mode 100644 index 0000000000..af37329352 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerExporterWrapper.java @@ -0,0 +1,90 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.listener; + +import java.util.List; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.ExporterListener; +import com.alibaba.dubbo.rpc.Invoker; + +/** + * ListenerExporter + * + * @author william.liangf + */ +public class ListenerExporterWrapper implements Exporter { + + private static final Logger logger = LoggerFactory.getLogger(ListenerExporterWrapper.class); + + private final Exporter exporter; + + private final List listeners; + + public ListenerExporterWrapper(Exporter exporter, List listeners){ + if (exporter == null) { + throw new IllegalArgumentException("exporter == null"); + } + this.exporter = exporter; + this.listeners = listeners; + if (listeners != null && listeners.size() > 0) { + RuntimeException exception = null; + for (ExporterListener listener : listeners) { + if (listener != null) { + try { + listener.exported(this); + } catch (RuntimeException t) { + logger.error(t.getMessage(), t); + exception = t; + } + } + } + if (exception != null) { + throw exception; + } + } + } + + public Invoker getInvoker() { + return exporter.getInvoker(); + } + + public void unexport() { + try { + exporter.unexport(); + } finally { + if (listeners != null && listeners.size() > 0) { + RuntimeException exception = null; + for (ExporterListener listener : listeners) { + if (listener != null) { + try { + listener.unexported(this); + } catch (RuntimeException t) { + logger.error(t.getMessage(), t); + exception = t; + } + } + } + if (exception != null) { + throw exception; + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java new file mode 100644 index 0000000000..767c7338a9 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/listener/ListenerInvokerWrapper.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.listener; + +import java.util.List; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.InvokerListener; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * ListenerInvoker + * + * @author william.liangf + */ +public class ListenerInvokerWrapper implements Invoker { + + private static final Logger logger = LoggerFactory.getLogger(ListenerInvokerWrapper.class); + + private final Invoker invoker; + + private final List listeners; + + public ListenerInvokerWrapper(Invoker invoker, List listeners){ + if (invoker == null) { + throw new IllegalArgumentException("invoker == null"); + } + this.invoker = invoker; + this.listeners = listeners; + if (listeners != null && listeners.size() > 0) { + for (InvokerListener listener : listeners) { + if (listener != null) { + try { + listener.referred(invoker); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + } + } + + public Class getInterface() { + return invoker.getInterface(); + } + + public URL getUrl() { + return invoker.getUrl(); + } + + public boolean isAvailable() { + return invoker.isAvailable(); + } + + public Result invoke(Invocation invocation) throws RpcException { + return invoker.invoke(invocation); + } + + @Override + public String toString() { + return getInterface() + " -> " + getUrl()==null?" ":getUrl().toString(); + } + + public void destroy() { + try { + invoker.destroy(); + } finally { + if (listeners != null && listeners.size() > 0) { + for (InvokerListener listener : listeners) { + if (listener != null) { + try { + listener.destroyed(invoker); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/ProxyFactory.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/ProxyFactory.java new file mode 100644 index 0000000000..c5f7dd3da8 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/ProxyFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import com.alibaba.dubbo.common.Adaptive; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * ProxyFactory. (SPI, Singleton, ThreadSafe) + * + * @author william.liangf + */ +@Extension("javassist") +public interface ProxyFactory { + + /** + * create proxy. + * + * @param invoker + * @param types + * @return proxy + */ + @Adaptive({Constants.PROXY_KEY}) + T getProxy(Invoker invoker, Class... types) throws RpcException; + + /** + * create invoker. + * + * @param + * @param proxy + * @param type + * @param url + * @return invoker + */ + @Adaptive({Constants.PROXY_KEY}) + Invoker getInvoker(T proxy, Class type, URL url) throws RpcException; + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/InvokerHandler.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/InvokerHandler.java new file mode 100644 index 0000000000..2a1a42cab0 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/InvokerHandler.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.support; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcInvocation; + +/** + * InvokerHandler + * + * @author william.liangf + */ +public class InvokerHandler implements InvocationHandler { + + private final Invoker invoker; + + public InvokerHandler(Invoker handler){ + this.invoker = handler; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + Class[] parameterTypes = method.getParameterTypes(); + if (method.getDeclaringClass() == Object.class) { + return method.invoke(invoker, args); + } + if ("toString".equals(methodName) && parameterTypes.length == 0) { + return invoker.toString(); + } + if ("hashCode".equals(methodName) && parameterTypes.length == 0) { + return invoker.hashCode(); + } + if ("equals".equals(methodName) && parameterTypes.length == 1) { + return invoker.equals(args[0]); + } + return invoker.invoke(new RpcInvocation(method, args)).recreate(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/InvokerWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/InvokerWrapper.java new file mode 100644 index 0000000000..05c4988d70 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/InvokerWrapper.java @@ -0,0 +1,88 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.support; + +import java.lang.reflect.InvocationTargetException; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * InvokerWrapper + * + * @author william.liangf + */ +public abstract class InvokerWrapper implements Invoker { + + private final T proxy; + + private final Class type; + + private final URL url; + + public InvokerWrapper(T proxy, Class type, URL url){ + if (proxy == null) { + throw new IllegalArgumentException("proxy == null"); + } + if (type == null) { + throw new IllegalArgumentException("interface == null"); + } + if (! type.isInstance(proxy)) { + throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type); + } + this.proxy = proxy; + this.type = type; + this.url = url; + } + + public Class getInterface() { + return type; + } + + public URL getUrl() { + return url; + } + + public boolean isAvailable() { + return true; + } + + public void destroy() { + } + + public Result invoke(Invocation invocation) throws RpcException { + try { + return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments())); + } catch (InvocationTargetException e) { + return new RpcResult(e.getTargetException()); + } catch (Throwable e) { + throw new RpcException(e.getMessage(), e); + } + } + + protected abstract Object doInvoke(T proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable; + + @Override + public String toString() { + return getInterface() + " -> " + getUrl()==null?" ":getUrl().toString(); + } + + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/javassist/JavassistProxyFactory.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/javassist/JavassistProxyFactory.java new file mode 100644 index 0000000000..b4cafc683d --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/javassist/JavassistProxyFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.support.javassist; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.bytecode.Proxy; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.proxy.support.InvokerHandler; +import com.alibaba.dubbo.rpc.proxy.support.InvokerWrapper; + +/** + * JavaassistRpcProxyFactory + + * @author william.liangf + */ +@Extension("javassist") +public class JavassistProxyFactory implements ProxyFactory { + + @SuppressWarnings("unchecked") + public T getProxy(Invoker invoker, Class... types) { + Class[] interfaces; + if (types != null && types.length > 0) { + interfaces = new Class[types.length + 1]; + interfaces[0] = invoker.getInterface(); + System.arraycopy(types, 0, interfaces, 1, types.length); + } else { + interfaces = new Class[] {invoker.getInterface()}; + } + return (T) Proxy.getProxy(interfaces).newInstance(new InvokerHandler(invoker)); + } + + public Invoker getInvoker(T proxy, Class type, URL url) { + final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass()); + return new InvokerWrapper(proxy, type, url) { + @Override + protected Object doInvoke(T proxy, String methodName, + Class[] parameterTypes, + Object[] arguments) throws Throwable { + return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); + } + }; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/jdk/JdkProxyFactory.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/jdk/JdkProxyFactory.java new file mode 100644 index 0000000000..f1f1e31dc1 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/support/jdk/JdkProxyFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.support.jdk; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.proxy.support.InvokerHandler; +import com.alibaba.dubbo.rpc.proxy.support.InvokerWrapper; + +/** + * JavaassistRpcProxyFactory + + * @author william.liangf + */ +@Extension("jdk") +public class JdkProxyFactory implements ProxyFactory { + + @SuppressWarnings("unchecked") + public T getProxy(Invoker invoker, Class... types) { + Class[] interfaces; + if (types != null && types.length > 0) { + interfaces = new Class[types.length + 1]; + interfaces[0] = invoker.getInterface(); + System.arraycopy(types, 0, interfaces, 1, types.length); + } else { + interfaces = new Class[] {invoker.getInterface()}; + } + return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerHandler(invoker)); + } + + public Invoker getInvoker(T proxy, Class type, URL url) { + return new InvokerWrapper(proxy, type, url) { + @Override + protected Object doInvoke(T proxy, String methodName, + Class[] parameterTypes, + Object[] arguments) throws Throwable { + Method method = proxy.getClass().getMethod(methodName, parameterTypes); + return method.invoke(proxy, arguments); + } + }; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/EchoProxyFactoryWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/EchoProxyFactoryWrapper.java new file mode 100644 index 0000000000..8bc6664dad --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/EchoProxyFactoryWrapper.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.wrapper; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.service.EchoService; + +/** + * EchoProxyFactoryWrapper + * + * @author william.liangf + */ +public class EchoProxyFactoryWrapper implements ProxyFactory { + + private final ProxyFactory proxyFactory; + + public EchoProxyFactoryWrapper(ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + } + + private Class[] appendEchoService(Class[] types) { + if (types == null || types.length == 0) { + return new Class[] { EchoService.class }; + } else { + Class[] clses = new Class[types.length + 1]; + System.arraycopy(types, 0, clses, 0, types.length); + clses[types.length] = EchoService.class; + return clses; + } + } + + public T getProxy(Invoker invoker, Class... types) throws RpcException { + return proxyFactory.getProxy(invoker, appendEchoService(types)); + } + + public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { + return proxyFactory.getInvoker(proxy, type, url); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/MockInvoker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/MockInvoker.java new file mode 100644 index 0000000000..c512e2cfc6 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/MockInvoker.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.wrapper; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * MockInvoker + * + * @author william.liangf + */ +public class MockInvoker implements Invoker { + + private final Invoker invoker; + + private final Invoker mockInvoker; + + public MockInvoker(Invoker invoker, Invoker mockInvoker) { + this.invoker = invoker; + this.mockInvoker = mockInvoker; + } + + public Class getInterface() { + return invoker.getInterface(); + } + + public URL getUrl() { + return invoker.getUrl(); + } + + public boolean isAvailable() { + return invoker.isAvailable() && mockInvoker.isAvailable(); + } + + public Result invoke(Invocation invocation) throws RpcException { + try { + return invoker.invoke(invocation); + } catch (RpcException e) { + return mockInvoker.invoke(invocation); + } + } + + public void destroy() { + try { + invoker.destroy(); + } finally { + mockInvoker.destroy(); + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/MockProxyFactoryWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/MockProxyFactoryWrapper.java new file mode 100644 index 0000000000..39ca2299e7 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/MockProxyFactoryWrapper.java @@ -0,0 +1,77 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.wrapper; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * MockProxyFactoryWrapper + * + * @author william.liangf + */ +public class MockProxyFactoryWrapper implements ProxyFactory { + + private static final Logger LOGGER = LoggerFactory.getLogger(MockProxyFactoryWrapper.class); + + private final ProxyFactory proxyFactory; + + public MockProxyFactoryWrapper(ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + } + + @SuppressWarnings({ "unchecked"}) + public T getProxy(Invoker invoker, Class... types) throws RpcException { + String mock = invoker.getUrl().getParameter(Constants.MOCK_KEY); + if (ConfigUtils.isNotEmpty(mock) && GenericService.class != invoker.getInterface()) { + Class serviceType = invoker.getInterface(); + if (ConfigUtils.isDefault(mock)) { + mock = serviceType.getName() + "Mock"; + } + try { + Class mockClass = ReflectUtils.forName(mock); + if (! serviceType.isAssignableFrom(mockClass)) { + throw new IllegalArgumentException("The mock implemention class " + mockClass.getName() + " not implement interface " + serviceType.getName()); + } + try { + T mockObject = (T) mockClass.newInstance(); + invoker = new MockInvoker(invoker, proxyFactory.getInvoker(mockObject, invoker.getInterface(), invoker.getUrl())); + } catch (InstantiationException e) { + throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName(), e); + } + } catch (Throwable t) { + LOGGER.error("Failed to create mock implemention class " + mock + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t); + // ignore + } + } + return proxyFactory.getProxy(invoker, types); + } + + public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { + return proxyFactory.getInvoker(proxy, type, url); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java new file mode 100644 index 0000000000..0cafb2c9b7 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java @@ -0,0 +1,112 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy.wrapper; + +import java.lang.reflect.Constructor; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * StubProxyFactoryWrapper + * + * @author william.liangf + */ +public class StubProxyFactoryWrapper implements ProxyFactory { + + private static final Logger LOGGER = LoggerFactory.getLogger(StubProxyFactoryWrapper.class); + + private final ProxyFactory proxyFactory; + + private Protocol protocol; + + public StubProxyFactoryWrapper(ProxyFactory proxyFactory) { + this.proxyFactory = proxyFactory; + } + + public void setProtocol(Protocol protocol) { + this.protocol = protocol; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public T getProxy(Invoker invoker, Class... types) throws RpcException { + T proxy = proxyFactory.getProxy(invoker, types); + if (GenericService.class != invoker.getInterface()) { + String stub = invoker.getUrl().getParameter(Constants.STUB_KEY, invoker.getUrl().getParameter(Constants.LOCAL_KEY)); + if (ConfigUtils.isNotEmpty(stub)) { + Class serviceType = invoker.getInterface(); + if (ConfigUtils.isDefault(stub)) { + if (invoker.getUrl().hasParameter(Constants.STUB_KEY)) { + stub = serviceType.getName() + "Stub"; + } else { + stub = serviceType.getName() + "Local"; + } + } + try { + Class stubClass = ReflectUtils.forName(stub); + if (! serviceType.isAssignableFrom(stubClass)) { + throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + serviceType.getName()); + } + try { + Constructor constructor = ReflectUtils.findConstructor(stubClass, serviceType); + proxy = (T) constructor.newInstance(new Object[] {proxy}); + //export stub service + URL url = invoker.getUrl(); + if (url.getBooleanParameter(RpcConstants.STUB_EVENT_KEY, RpcConstants.DEFAULT_STUB_EVENT)){ + url = url.addParameter(RpcConstants.STUB_EVENT_METHODS_KEY, StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(), ",")); + url = url.addParameter(RpcConstants.IS_SERVER_KEY, Boolean.FALSE.toString()); + try{ + export(proxy, (Class)invoker.getInterface(), url); + }catch (Exception e) { + LOGGER.error("export a stub service error.", e); + } + } + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implemention class " + stubClass.getName(), e); + } + } catch (Throwable t) { + LOGGER.error("Failed to create stub implemention class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t); + // ignore + } + } + } + return proxy; + } + + public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { + return proxyFactory.getInvoker(proxy, type, url); + } + + private Exporter export(T instance, Class type, URL url) { + return protocol.export(proxyFactory.getInvoker(instance, type, url)); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/EchoService.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/EchoService.java new file mode 100644 index 0000000000..c09fcd9e90 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/EchoService.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.service; + +/** + * Echo service. + * + * @author qian.lei + */ +public interface EchoService { + + /** + * echo test. + * + * @param message message. + * @return message. + */ + Object $echo(Object message); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/GenericException.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/GenericException.java new file mode 100644 index 0000000000..81be78fa33 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/GenericException.java @@ -0,0 +1,59 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.service; + +import com.alibaba.dubbo.common.utils.StringUtils; + +/** + * GenericException + * + * @serial Don't change the class name and properties. + * @author william.liangf + */ +public class GenericException extends RuntimeException { + + private static final long serialVersionUID = -1182299763306599962L; + + private String exceptionClass; + + private String exceptionMessage; + + public GenericException() { + } + + public GenericException(Throwable cause) { + super(StringUtils.toString(cause)); + this.exceptionClass = cause.getClass().getName(); + this.exceptionMessage = cause.getMessage(); + } + + public String getExceptionClass() { + return exceptionClass; + } + + public void setExceptionClass(String exceptionClass) { + this.exceptionClass = exceptionClass; + } + + public String getExceptionMessage() { + return exceptionMessage; + } + + public void setExceptionMessage(String exceptionMessage) { + this.exceptionMessage = exceptionMessage; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/GenericService.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/GenericService.java new file mode 100644 index 0000000000..e8a0e3f3dc --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/service/GenericService.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.service; + +/** + * 通用服务接口 + * + * @author william.liangf + */ +public interface GenericService { + + /** + * 泛化调用 + * + * @param method 方法名,如:findPerson,如果有重载方法,需带上参数列表,如:findPerson(java.lang.String) + * @param parameterTypes 参数类型 + * @param args 参数列表 + * @return 返回值 + * @throws Throwable 方法抛出的异常 + */ + Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException; + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractExporter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractExporter.java new file mode 100644 index 0000000000..254dc7abaf --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractExporter.java @@ -0,0 +1,110 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.net.InetSocketAddress; + +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; + +/** + * AbstractExporter. + * + * @author qianlei + * @author william.liangf + */ +public abstract class AbstractExporter implements Exporter { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final Invoker invoker; + + private volatile boolean unexported = false; + + public AbstractExporter(Invoker invoker) { + if(invoker == null) + throw new IllegalStateException("service invoker == null"); + if(invoker.getInterface() == null) + throw new IllegalStateException("service type == null"); + if(invoker.getUrl() == null) + throw new IllegalStateException("service url == null"); + this.invoker = invoker; + } + + public Invoker getInvoker() { + return invoker; + } + + public void unexport() { + if (unexported) + throw new IllegalStateException("The exporter " + this + " unexported!"); + unexported = true; + getInvoker().destroy(); + } + + public String toString() { + return getInvoker().toString(); + } + + /** + * invoke. + * + * + * Context.getContext().setRemoteAddress(remoteAddress); + * getInvoker().invoke(invocation); + * + * + * @param invocation + * @param remoteAddress + * @return + * @throws RpcException + */ + public Result invoke(Invocation invocation, InetSocketAddress remoteAddress) throws RpcException { + RpcContext.getContext().setRemoteAddress(remoteAddress); + return getInvoker().invoke(invocation); + } + + /** + * invoke. + * + * + * Context.getContext().setRemoteAddress(remoteHost, remotePort); + * getInvoker().invoke(invocation); + * + * + * @param invocation + * @param remoteHost + * @param remotePort + * @return + * @throws RpcException + */ + public Result invoke(Invocation invocation, String remoteHost, int remotePort) throws RpcException { + if (remoteHost != null && remoteHost.length() > 0) { + if (remotePort < 0) { + remotePort = 0; + } + RpcContext.getContext().setRemoteAddress(remoteHost, remotePort); + } + return getInvoker().invoke(invocation); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractInvoker.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractInvoker.java new file mode 100644 index 0000000000..8f06e44638 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractInvoker.java @@ -0,0 +1,161 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.Version; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * AbstractInvoker. + * + * @author qian.lei + * @author william.liangf + */ +public abstract class AbstractInvoker implements Invoker { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final Class type; + + private final URL url; + + private final Map attachment; + + private volatile boolean available = true; + + private volatile boolean destroyed = false; + + public AbstractInvoker(Class type, URL url){ + this(type, url, (Map) null); + } + + public AbstractInvoker(Class type, URL url, String[] keys) { + this(type, url, convertAttachment(url, keys)); + } + + public AbstractInvoker(Class type, URL url, Map attachment) { + if (type == null) + throw new IllegalArgumentException("service type == null"); + if (url == null) + throw new IllegalArgumentException("service url == null"); + this.type = type; + this.url = url; + this.attachment = attachment == null ? null : Collections.unmodifiableMap(attachment); + } + + private static Map convertAttachment(URL url, String[] keys) { + if (keys == null || keys.length == 0) { + return null; + } + Map attachment = new HashMap(); + for (String key : keys) { + String value = url.getParameter(key); + if (value != null && value.length() > 0) { + attachment.put(key, value); + } + } + return attachment; + } + + public Class getInterface() { + return type; + } + + public URL getUrl() { + return url; + } + + public boolean isAvailable() { + return available; + } + + protected void setAvailable(boolean available) { + this.available = available; + } + + public void destroy() { + if (destroyed) + throw new IllegalStateException("The invoker " + this + " destroyed!"); + destroyed = true; + setAvailable(false); + } + + public String toString() { + return getInterface() + " -> " + getUrl()==null?" ":getUrl().toString(); + } + + public Result invoke(Invocation inv) throws RpcException { + if(destroyed) + throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + + " use dubbo version " + Version.getVersion() + + " is DESTROYED, can not be invoked any more!"); + RpcInvocation invocation = (RpcInvocation) inv; + Map attachments = new HashMap(); + if (attachment != null && attachment.size() > 0) { + attachments.putAll(attachment); + } + Map context = RpcContext.getContext().getAttachments(); + if (context != null) { + attachments.putAll(context); + } + if (invocation.getAttachments() != null) { + attachments.putAll(invocation.getAttachments()); + } + invocation.setAttachments(attachments); + RpcResult result = new RpcResult(); + try { + Object obj = doInvoke(invocation); + result.setResult(obj); + } catch (InvocationTargetException e) { // biz exception + Throwable te = e.getTargetException(); + if (te == null) { + result.setException(e); + } else { + if (te instanceof RpcException) { + ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION); + } + result.setException(te); + } + } catch (RpcException e) { + if (e.isBiz()) { + result.setException(e); + } else { + throw e; + } + } catch (Throwable e) { + result.setException(e); + } + return result; + } + + protected abstract Object doInvoke(Invocation invocation) throws Throwable; + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractProtocol.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractProtocol.java new file mode 100644 index 0000000000..5e80c879a6 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/AbstractProtocol.java @@ -0,0 +1,117 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; + +/** + * abstract ProtocolSupport. + * + * @author qian.lei + * @author william.liangf + */ +public abstract class AbstractProtocol implements Protocol { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + protected final Map> exporterMap = new ConcurrentHashMap>(); + + protected final Set> invokers = new ConcurrentHashSet>(); + + protected static String serviceKey(URL url) { + return serviceKey(url.getPort(), url.getPath(), url.getParameter(Constants.VERSION_KEY), + url.getParameter(Constants.GROUP_KEY)); + } + + protected static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) { + StringBuilder buf = new StringBuilder(); + if (serviceGroup != null && serviceGroup.length() > 0) { + buf.append(serviceGroup); + buf.append("/"); + } + buf.append(serviceName); + if (serviceVersion != null && serviceVersion.length() > 0 && ! "0.0.0".equals(serviceVersion)) { + buf.append(":"); + buf.append(serviceVersion); + } + buf.append(":"); + buf.append(port); + return buf.toString(); + } + + public void destroy() { + for (Invoker invoker : invokers){ + if (invoker != null) { + invokers.remove(invoker); + try { + if (logger.isInfoEnabled()) { + logger.info("Destroy reference: " + invoker.getUrl()); + } + invoker.destroy(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + for (String key : new ArrayList(exporterMap.keySet())) { + Exporter exporter = exporterMap.remove(key); + if (exporter != null) { + try { + if (logger.isInfoEnabled()) { + logger.info("Unexport service: " + exporter.getInvoker().getUrl()); + } + exporter.unexport(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + } + @SuppressWarnings("deprecation") + protected static int getServerShutdownTimeout() { + int timeout = RpcConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT; + String value = System.getProperty(RpcConstants.SHUTDOWN_TIMEOUT_KEY); + if (value != null && value.length() > 0) { + try{ + timeout = Integer.parseInt(value); + }catch (Exception e) { + } + } else { + value = System.getProperty(RpcConstants.SHUTDOWN_TIMEOUT_SECONDS_KEY); + if (value != null && value.length() > 0) { + try{ + timeout = Integer.parseInt(value) * 1000; + }catch (Exception e) { + } + } + } + + return timeout; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/FutureAdapter.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/FutureAdapter.java new file mode 100644 index 0000000000..44d7f1d4af --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/FutureAdapter.java @@ -0,0 +1,83 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * FutureAdapter + * + * @author william.liangf + */ +public class FutureAdapter implements Future { + + private final ResponseFuture future; + + public FutureAdapter(ResponseFuture future){ + this.future = future; + } + + public ResponseFuture getFuture() { + return future; + } + + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + public boolean isCancelled() { + return false; + } + + public boolean isDone() { + return future.isDone(); + } + + @SuppressWarnings("unchecked") + public V get() throws InterruptedException, ExecutionException { + try { + return (V) (((Result) future.get()).recreate()); + } catch (RemotingException e) { + throw new ExecutionException(e.getMessage(), e); + } catch (Throwable e) { + throw new RpcException(e); + } + } + + @SuppressWarnings("unchecked") + public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + int timeoutInMillis = (int) unit.convert(timeout, TimeUnit.MILLISECONDS); + try { + return (V) (((Result) future.get(timeoutInMillis)).recreate()); + } catch (com.alibaba.dubbo.remoting.TimeoutException e) { + throw new TimeoutException(StringUtils.toString(e)); + } catch (RemotingException e) { + throw new ExecutionException(e.getMessage(), e); + } catch (Throwable e) { + throw new RpcException(e); + } + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/InvokerWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/InvokerWrapper.java new file mode 100644 index 0000000000..3a0511c3c9 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/InvokerWrapper.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * InvokerWrapper + * + * @author william.liangf + */ +public class InvokerWrapper implements Invoker { + + private final Invoker invoker; + + private final URL url; + + public InvokerWrapper(Invoker invoker, URL url){ + this.invoker = invoker; + this.url = url; + } + + public Class getInterface() { + return invoker.getInterface(); + } + + public URL getUrl() { + return url; + } + + public boolean isAvailable() { + return invoker.isAvailable(); + } + + public Result invoke(Invocation invocation) throws RpcException { + return invoker.invoke(invocation); + } + + public void destroy() { + invoker.destroy(); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/ProtocolFilterWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/ProtocolFilterWrapper.java new file mode 100644 index 0000000000..7b3438f437 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/ProtocolFilterWrapper.java @@ -0,0 +1,117 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * ListenerProtocol + * + * @author william.liangf + */ +public class ProtocolFilterWrapper implements Protocol { + + private final Protocol protocol; + + public ProtocolFilterWrapper(Protocol protocol){ + if (protocol == null) { + throw new IllegalArgumentException("protocol == null"); + } + this.protocol = protocol; + } + + public int getDefaultPort() { + return protocol.getDefaultPort(); + } + + public Exporter export(Invoker invoker) throws RpcException { + if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { + return protocol.export(invoker); + } + return protocol.export(buildInvokerChain(invoker, invoker.getUrl().getParameter(Constants.SERVICE_FILTER_KEY), RpcConstants.DEFAULT_SERVICE_FILTERS)); + } + + public Invoker refer(Class type, URL url) throws RpcException { + if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { + return protocol.refer(type, url); + } + return buildInvokerChain(protocol.refer(type, url), url.getParameter(Constants.REFERENCE_FILTER_KEY), RpcConstants.DEFAULT_REFERENCE_FILTERS); + } + + public void destroy() { + protocol.destroy(); + } + + private static Invoker buildInvokerChain(final Invoker invoker, String config, List defaults) { + List names = ConfigUtils.mergeValues(Filter.class, config, defaults); + Invoker last = invoker; + if (names.size() > 0) { + List filters = new ArrayList(names.size()); + for (String name : names) { + filters.add(ExtensionLoader.getExtensionLoader(Filter.class).getExtension(name)); + } + if (filters.size() > 0) { + for (int i = filters.size() - 1; i >= 0; i --) { + final Filter filter = filters.get(i); + final Invoker next = last; + last = new Invoker() { + + public Class getInterface() { + return invoker.getInterface(); + } + + public URL getUrl() { + return invoker.getUrl(); + } + + public boolean isAvailable() { + return invoker.isAvailable(); + } + + public Result invoke(Invocation invocation) throws RpcException { + return filter.invoke(next, invocation); + } + + public void destroy() { + invoker.destroy(); + } + + @Override + public String toString() { + return invoker.toString(); + } + }; + } + } + } + return last; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/ProtocolListenerWrapper.java b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/ProtocolListenerWrapper.java new file mode 100644 index 0000000000..c683e4c426 --- /dev/null +++ b/dubbo-rpc/src/main/java/com/alibaba/dubbo/rpc/support/ProtocolListenerWrapper.java @@ -0,0 +1,99 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.ConfigUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.ExporterListener; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.InvokerListener; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.listener.ListenerExporterWrapper; +import com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper; + +/** + * ListenerProtocol + * + * @author william.liangf + */ +public class ProtocolListenerWrapper implements Protocol { + + private final Protocol protocol; + + public ProtocolListenerWrapper(Protocol protocol){ + if (protocol == null) { + throw new IllegalArgumentException("protocol == null"); + } + this.protocol = protocol; + } + + public int getDefaultPort() { + return protocol.getDefaultPort(); + } + + public Exporter export(Invoker invoker) throws RpcException { + if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { + return protocol.export(invoker); + } + return new ListenerExporterWrapper(protocol.export(invoker), + buildServiceListeners(invoker.getUrl().getParameter(Constants.EXPORTER_LISTENER_KEY), RpcConstants.DEFAULT_EXPORTER_LISTENERS)); + } + + public Invoker refer(Class type, URL url) throws RpcException { + if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { + return protocol.refer(type, url); + } + return new ListenerInvokerWrapper(protocol.refer(type, url), + buildReferenceListeners(url.getParameter(Constants.INVOKER_LISTENER_KEY), RpcConstants.DEFAULT_INVOKER_LISTENERS)); + } + + public void destroy() { + protocol.destroy(); + } + + private static List buildServiceListeners(String config, List defaults) { + List names = ConfigUtils.mergeValues(Filter.class, config, defaults); + List listeners = new ArrayList(); + if (names.size() > 0) { + for (String name : names) { + listeners.add(ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(name)); + } + } + return Collections.unmodifiableList(listeners); + } + + private static List buildReferenceListeners(String config, List defaults) { + List names = ConfigUtils.mergeValues(Filter.class, config, defaults); + List listeners = new ArrayList(); + if (names.size() > 0) { + for (String name : names) { + listeners.add(ExtensionLoader.getExtensionLoader(InvokerListener.class).getExtension(name)); + } + } + return Collections.unmodifiableList(listeners); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker new file mode 100644 index 0000000000..0c8334edc6 --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.common.status.StatusChecker @@ -0,0 +1,2 @@ +com.alibaba.dubbo.rpc.dubbo.status.ServerStatusChecker +com.alibaba.dubbo.rpc.dubbo.status.ThreadPoolStatusChecker \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Codec b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Codec new file mode 100644 index 0000000000..f932f0ad53 --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.Codec @@ -0,0 +1 @@ +com.alibaba.dubbo.rpc.dubbo.DubboCodec \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.telnet.TelnetHandler b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.telnet.TelnetHandler new file mode 100644 index 0000000000..03eb87444e --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.remoting.telnet.TelnetHandler @@ -0,0 +1,8 @@ +com.alibaba.dubbo.rpc.dubbo.telnet.ListTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.ChangeTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.CurrentTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.InvokeTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.TraceTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.CountTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.PortTelnetHandler +com.alibaba.dubbo.rpc.dubbo.telnet.LogTelnetHandler \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Filter b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Filter new file mode 100644 index 0000000000..8bfa66eab0 --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Filter @@ -0,0 +1,17 @@ +com.alibaba.dubbo.rpc.filter.EchoFilter +com.alibaba.dubbo.rpc.filter.GenericFilter +com.alibaba.dubbo.rpc.filter.GenericImplFilter +com.alibaba.dubbo.rpc.filter.TokenFilter +com.alibaba.dubbo.rpc.filter.AccessLogFilter +com.alibaba.dubbo.rpc.filter.ActiveLimitFilter +com.alibaba.dubbo.rpc.filter.ClassLoaderFilter +com.alibaba.dubbo.rpc.filter.ContextFilter +com.alibaba.dubbo.rpc.filter.ConsumerContextFilter +com.alibaba.dubbo.rpc.filter.ExceptionFilter +com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter +com.alibaba.dubbo.rpc.filter.DeprecatedFilter +com.alibaba.dubbo.rpc.filter.TraceFilter +com.alibaba.dubbo.rpc.filter.CompatibleFilter +com.alibaba.dubbo.rpc.filter.ReadyFilter +com.alibaba.dubbo.rpc.filter.TimeoutFilter +com.alibaba.dubbo.rpc.filter.EventFilter \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.InvokerListener b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.InvokerListener new file mode 100644 index 0000000000..014211c194 --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.InvokerListener @@ -0,0 +1 @@ +com.alibaba.dubbo.rpc.listener.DeprecatedInvokerListener \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol new file mode 100644 index 0000000000..b767d599d5 --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.Protocol @@ -0,0 +1,4 @@ +com.alibaba.dubbo.rpc.support.ProtocolFilterWrapper +com.alibaba.dubbo.rpc.support.ProtocolListenerWrapper +com.alibaba.dubbo.rpc.injvm.InjvmProtocol +com.alibaba.dubbo.rpc.dubbo.DubboProtocol \ No newline at end of file diff --git a/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.proxy.ProxyFactory b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.proxy.ProxyFactory new file mode 100644 index 0000000000..a638a373a5 --- /dev/null +++ b/dubbo-rpc/src/main/resources/META-INF/services/com.alibaba.dubbo.rpc.proxy.ProxyFactory @@ -0,0 +1,5 @@ +com.alibaba.dubbo.rpc.proxy.wrapper.EchoProxyFactoryWrapper +com.alibaba.dubbo.rpc.proxy.wrapper.MockProxyFactoryWrapper +com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper +com.alibaba.dubbo.rpc.proxy.support.jdk.JdkProxyFactory +com.alibaba.dubbo.rpc.proxy.support.javassist.JavassistProxyFactory \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/CustomArgument.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/CustomArgument.java new file mode 100644 index 0000000000..414c81e86d --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/CustomArgument.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.io.Serializable; + +import com.alibaba.dubbo.rpc.support.Type; + +/** + * @author chao.liuc + * + */ +@SuppressWarnings("serial") +public class CustomArgument implements Serializable{ + + public CustomArgument(){} + + public CustomArgument(Type type, String name) { + super(); + this.type = type; + this.name = name; + } + Type type; + String name; + public Type getType() { + return type; + } + public void setType(Type type) { + this.type = type; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/DemoRequest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/DemoRequest.java new file mode 100644 index 0000000000..665180d5c5 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/DemoRequest.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import java.io.Serializable; + +/** + * TestRequest. + * + * @author qian.lei + */ + +class DemoRequest implements Serializable +{ + private static final long serialVersionUID = -2579095288792344869L; + + private String mServiceName; + + private String mMethodName; + + private Class[] mParameterTypes; + + private Object[] mArguments; + + public DemoRequest(String serviceName,String methodName, Class[] parameterTypes,Object[] args) + { + mServiceName = serviceName; + mMethodName = methodName; + mParameterTypes = parameterTypes; + mArguments = args; + } + + public String getServiceName() + { + return mServiceName; + } + + public String getMethodName() + { + return mMethodName; + } + + public Class[] getParameterTypes() { + return mParameterTypes; + } + + public Object[] getArguments() + { + return mArguments; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/ProtocolTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/ProtocolTest.java new file mode 100644 index 0000000000..5ddff56602 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/ProtocolTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.containsString; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.support.IEcho; + +/** + * @author ding.lid + */ +public class ProtocolTest { + + IEcho echo = new IEcho() { + public String echo(String e) { + return e; + } + }; + + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension("javassist"); + + URL url = URL.valueOf("injvm://localhost:100/com.alibaba.dubbo.rpc.support.IEcho"); + + Invoker invoker = proxyFactory.getInvoker(echo, IEcho.class, url); + + @Test + public void test_destroyWontCloseAllProtocol() throws Exception { + Protocol autowireProtocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + Protocol InjvmProtocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("injvm"); + + InjvmProtocol.export(invoker); + + Invoker refer = InjvmProtocol.refer(IEcho.class, url); + IEcho echoProxy = proxyFactory.getProxy(refer); + + assertEquals("ok", echoProxy.echo("ok")); + + try { + autowireProtocol.destroy(); + } catch (UnsupportedOperationException expected) { + assertThat(expected.getMessage(), containsString("of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!")); + } + + assertEquals("ok2", echoProxy.echo("ok2")); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/ProtocolUtils.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/ProtocolUtils.java new file mode 100644 index 0000000000..8861c24ec8 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/ProtocolUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; + +/** + * TODO Comment of ProtocolUtils + * @author william.liangf + * + */ +public class ProtocolUtils { + + private static Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private static ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + public static T refer(Class type, String url) { + return refer(type, URL.valueOf(url)); + } + + public static T refer(Class type, URL url) { + return proxy.getProxy(protocol.refer(type, url)); + } + + public static Exporter export(T instance, Class type, String url) { + return export(instance, type, URL.valueOf(url)); + } + + public static Exporter export(T instance, Class type, URL url) { + return protocol.export(proxy.getInvoker(instance, type, url)); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/callback/ExplicitCallbackTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/callback/ExplicitCallbackTest.java new file mode 100644 index 0000000000..8a324ec9ce --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/callback/ExplicitCallbackTest.java @@ -0,0 +1,339 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.callback; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.ProtocolUtils; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; + +public class ExplicitCallbackTest { + + protected Exporter exporter = null; + protected Invoker reference = null; + + @After + public void tearDown(){ + destroyService(); + } + + public void exportService(){ + exporter = ProtocolUtils.export(new DemoServiceImpl(), IDemoService.class, serviceURL); + } + void referService() { + demoProxy = (IDemoService)ProtocolUtils.refer(IDemoService.class, consumerUrl); + } + + protected URL serviceURL = null ; + protected URL consumerUrl = null ; + + @Before + public void setUp(){ + } + public void initOrResetUrl(int callbacks, int timeout) throws Exception { + int port = NetUtils.getAvailablePort() ; + consumerUrl = serviceURL = URL.valueOf("dubbo://127.0.0.1:"+port+"/"+IDemoService.class.getName()+"?group=test" + +"&xxx.0.callback=true" + +"&xxx2.0.callback=true" + +"&unxxx2.0.callback=false" + +"&timeout="+timeout + +"&"+RpcConstants.CALLBACK_INSTANCES_LIMIT_KEY+"="+callbacks + ); + // uncomment is unblock invoking +// serviceURL = serviceURL.addParameter("yyy."+Constants.ASYNC_KEY,String.valueOf(true)); +// consumerUrl = consumerUrl.addParameter("yyy."+Constants.ASYNC_KEY,String.valueOf(true)); + } + public void initOrResetBadUrl() throws Exception{ + initOrResetUrl(1, 1000); + consumerUrl = serviceURL = serviceURL + .addParameter(Constants.DOWNSTREAM_CODEC_KEY, "dubbo1compatible") + ; + } + public void initOrResetService(){ + destroyService(); + exportService(); + referService(); + } + public void destroyService(){ + demoProxy = null ; + try { + if (exporter!=null) exporter.unexport(); + if (reference!=null) reference.destroy(); + }catch (Exception e) { + } + } + // ============================华丽的分割线================================================ + interface IDemoCallback{ + String yyy(String msg); + } + interface IDemoService{ + public String get(); + public int getCallbackCount(); + public void xxx(IDemoCallback callback,String arg1,int runs,int sleep); + public void xxx2(IDemoCallback callback); + public void unxxx2(IDemoCallback callback); + } + + class DemoServiceImpl implements IDemoService { + public String get(){ + return "ok" ; + } + public void xxx(final IDemoCallback callback ,String arg1, final int runs ,final int sleep) { + callback.yyy("Sync callback msg .This is callback data. arg1:"+arg1); + Thread t = new Thread(new Runnable() { + public void run() { + for(int i = 0 ;i< runs ;i++){ + String ret = callback.yyy("server invoke callback : arg:"+System.currentTimeMillis()); + System.out.println("callback result is :"+ret); + try { + Thread.sleep(sleep); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }); + t.setDaemon(true); + t.start(); + System.out.println("xxx invoke complete"); + } + + private List callbacks = new ArrayList(); + public int getCallbackCount(){ + return callbacks.size(); + } + public void xxx2(IDemoCallback callback){ + if (!callbacks.contains(callback)){ + callbacks.add(callback); + } + startThread(); + } + private volatile Thread t = null; + private volatile Lock lock = new ReentrantLock(); + private void startThread(){ + if (t == null || callbacks.size() == 0){ + try{ + lock.lock(); + t = new Thread(new Runnable() { + public void run() { + while(callbacks.size()>0){ + try { + List callbacksCopy = new ArrayList(callbacks); + for(IDemoCallback callback : callbacksCopy){ + try{ + callback.yyy("this is callback msg,current time is :"+ System.currentTimeMillis()); + }catch (Exception e) { + e.printStackTrace(); + callbacks.remove(callback); + } + } + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }); + t.setDaemon(true); + t.start(); + }finally{ + lock.unlock(); + } + } + } + + public void unxxx2(IDemoCallback callback) { + if (!callbacks.contains(callback)){ + throw new IllegalStateException("callback instance not found"); + } + callbacks.remove(callback); + } + } + + + // ============================华丽的分割线================================================ + IDemoService demoProxy = null; + @Test + public void TestCallbackNormal() throws Exception { + initOrResetUrl(1, 1000); initOrResetService() ; + final AtomicInteger count = new AtomicInteger(0); + + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + count.incrementAndGet(); + return "ok"; + } + },"other custom args" , 10 , 100); + System.out.println("Async..."); + assertCallbackCount(10,100,count); + destroyService(); + } + + @Test + public void TestCallbackMultiInstans() throws Exception { + initOrResetUrl(2, 1000); + initOrResetService() ; + IDemoCallback callback = new IDemoCallback(){ + public String yyy(String msg) { + System.out.println("callback1:"+msg); + return "callback1 onChanged ,"+msg; + } + }; + + IDemoCallback callback2 = new IDemoCallback(){ + public String yyy(String msg) { + System.out.println("callback2:"+msg); + return "callback2 onChanged ,"+msg; + } + }; + { + demoProxy.xxx2(callback); + Assert.assertEquals(1, demoProxy.getCallbackCount()); + Thread.sleep(500); + demoProxy.unxxx2(callback); + Assert.assertEquals(0, demoProxy.getCallbackCount()); + System.out.println(""); + + demoProxy.xxx2(callback2); + Assert.assertEquals(1, demoProxy.getCallbackCount()); + Thread.sleep(500); + demoProxy.unxxx2(callback2); + Assert.assertEquals(0, demoProxy.getCallbackCount()); + System.out.println(""); + demoProxy.xxx2(callback); + Thread.sleep(500); + Assert.assertEquals(1, demoProxy.getCallbackCount()); + demoProxy.unxxx2(callback); + Assert.assertEquals(0, demoProxy.getCallbackCount()); + } + { + demoProxy.xxx2(callback); + Assert.assertEquals(1, demoProxy.getCallbackCount()); + + demoProxy.xxx2(callback); + Assert.assertEquals(1, demoProxy.getCallbackCount()); + + demoProxy.xxx2(callback2); + Assert.assertEquals(2, demoProxy.getCallbackCount()); + } + destroyService(); + } + + @Ignore + @Test(expected=RpcException.class) + public void TestCallbackDownStreamCodec() throws Exception { + initOrResetBadUrl(); initOrResetService() ; + final AtomicInteger count = new AtomicInteger(0); + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + count.incrementAndGet(); + return "ok"; + } + },"other custom args" , 10 , 100); + System.out.println("Async..."); + assertCallbackCount(10,100,count); + destroyService(); + } + + @Test(expected = RpcException.class) + public void TestCallbackConsumerLimit() throws Exception { + initOrResetUrl(1, 1000); + //api的方式 url 无法自动从服务端传递到客户端,需要手动制定 + initOrResetService() ; + final AtomicInteger count = new AtomicInteger(0); + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + count.incrementAndGet(); + return "ok"; + } + },"other custom args" , 10 , 100); + + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + count.incrementAndGet(); + return "ok"; + } + },"other custom args" , 10 , 100); + destroyService(); + } + + @Test(expected = RpcException.class) + public void TestCallbackProviderLimit() throws Exception { + initOrResetUrl(1, 1000); + //api的方式 url 无法自动从服务端传递到客户端,需要手动制定 + serviceURL = serviceURL.addParameter(RpcConstants.CALLBACK_INSTANCES_LIMIT_KEY, 1+""); + initOrResetService() ; + final AtomicInteger count = new AtomicInteger(0); + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + count.incrementAndGet(); + return "ok"; + } + },"other custom args" , 10 , 100); + + demoProxy.xxx(new IDemoCallback() { + public String yyy(String msg) { + System.out.println("Recived callback: " + msg); + count.incrementAndGet(); + return "ok"; + } + },"other custom args" , 10 , 100); + destroyService(); + } + + private void assertCallbackCount(int runs, int sleep, AtomicInteger count) throws InterruptedException{ + int last = count.get(); + for(int i=0;i< runs ;i++){ + if (last > runs) break; + Thread.sleep(sleep * 2); + System.out.println(count.get() + " " + last); + Assert.assertTrue(count.get() > last); + last = count.get(); + } + //有一次同步调用callback + Assert.assertEquals(runs+1, count.get()); + } + + @Ignore //使用不同进程启动 + @Test + public void startProvider() throws Exception { + exportService(); + synchronized (ExplicitCallbackTest.class) { + ExplicitCallbackTest.class.wait(); + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/callback/ImplicitCallBackTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/callback/ImplicitCallBackTest.java new file mode 100644 index 0000000000..50e0f2f419 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/callback/ImplicitCallBackTest.java @@ -0,0 +1,367 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.callback; + + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.ProtocolUtils; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.StaticContext; + +public class ImplicitCallBackTest{ + + protected Exporter exporter = null; + protected Invoker reference = null; + + protected URL serviceURL = null ; + protected URL consumerUrl = null ; + Method onReturnMethod; + Method onThrowMethod ; + Method onInvokeMethod ; + + @Before + public void setUp() throws SecurityException, NoSuchMethodException{ + onReturnMethod = Nofify.class.getMethod("onreturn", new Class[]{Person.class, Integer.class}); + onThrowMethod = Nofify.class.getMethod("onthrow", new Class[]{Throwable.class, Integer.class}); + onInvokeMethod = Nofify.class.getMethod("oninvoke", new Class[]{Integer.class}); + } + + public void initOrResetService(){ + destroyService(); + exportService(); + referService(); + } + public void destroyService(){ + demoProxy = null ; + try { + if (exporter!=null) exporter.unexport(); + if (reference!=null) reference.destroy(); + }catch (Exception e) { + } + } + + void referService() { + demoProxy = (IDemoService)ProtocolUtils.refer(IDemoService.class, consumerUrl); + } + + public void exportService(){ + exporter = ProtocolUtils.export(new NormalDemoService(), IDemoService.class, serviceURL); + } + public void exportExService(){ + exporter = ProtocolUtils.export(new ExceptionDemoExService(), IDemoService.class, serviceURL); + } + + public void initOrResetUrl(boolean isAsync) throws Exception { + int port = NetUtils.getAvailablePort() ; + consumerUrl = serviceURL = URL.valueOf("dubbo://127.0.0.1:"+port+"/"+IDemoService.class.getName()+"?group=test&async="+isAsync+"&timeout=100000&reference.filter=event" ); + StaticContext.getSystemContext().clear(); + } + + public void initImplicitCallBackURL_onlyOnthrow() throws Exception { + StaticContext.getSystemContext().put(StaticContext.getKey(consumerUrl, "get", RpcConstants.ON_THROW_METHOD_KEY),onThrowMethod); + StaticContext.getSystemContext().put(StaticContext.getKey(consumerUrl, "get", RpcConstants.ON_THROW_INSTANCE_KEY),notify); + } + public void initImplicitCallBackURL_onlyOnreturn() throws Exception { + StaticContext.getSystemContext().put(StaticContext.getKey(consumerUrl, "get", RpcConstants.ON_RETURN_METHOD_KEY),onReturnMethod); + StaticContext.getSystemContext().put(StaticContext.getKey(consumerUrl, "get", RpcConstants.ON_RETURN_INSTANCE_KEY),notify); + + } + public void initImplicitCallBackURL_onlyOninvoke() throws Exception { + StaticContext.getSystemContext().put(StaticContext.getKey(consumerUrl, "get", RpcConstants.ON_INVOKE_METHOD_KEY),onInvokeMethod); + StaticContext.getSystemContext().put(StaticContext.getKey(consumerUrl, "get", RpcConstants.ON_INVOKE_INSTANCE_KEY),notify); + } + + //================================================================================================ + + NofifyImpl notify = new NofifyImpl(); + + interface Nofify { + public void onreturn(Person msg, Integer id); + public void onthrow(Throwable ex, Integer id); + public void oninvoke(Integer id); + } + class NofifyImpl implements Nofify{ + public List inv = new ArrayList (); + public Map ret = new HashMap (); + public Map errors = new HashMap (); + public boolean exd = false; + public void onreturn(Person msg, Integer id) { + System.out.println("onNotify:"+msg); + ret.put(id, msg); + } + public void onthrow(Throwable ex, Integer id) { + errors.put(id, ex); +// ex.printStackTrace(); + } + public void oninvoke(Integer id) { + inv.add(id); + } + } + + interface IDemoService{ + public Person get(int id); + } + + class NormalDemoService implements IDemoService { + public Person get(int id){ + return new Person(id, "charles", 4); + } + } + class ExceptionDemoExService implements IDemoService { + public Person get(int id){ + throw new RuntimeException("request persion id is :"+ id); + } + } + + public static class Person implements Serializable{ + private static final long serialVersionUID = 1L; + public Person(int id, String name, int age) { + this.id = id; + this.name = name; + this.age = age; + } + private int id; + private String name ; + private int age; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + @Override + public String toString() { + return "Person [name=" + name + ", age=" + age + "]"; + } + } + //================================================================================================ + IDemoService demoProxy = null; + + @Test + public void test_CloseCallback() throws Exception { + initOrResetUrl(false); + initOrResetService() ; + Person ret = demoProxy.get(1); + Assert.assertEquals(1, ret.getId()); + destroyService(); + } + + @Test + public void test_Sync_Onreturn() throws Exception { + initOrResetUrl(false); + initImplicitCallBackURL_onlyOnreturn(); + initOrResetService() ; + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(requestId, ret.getId()); + for (int i = 0; i < 10; i++) { + if (! notify.ret.containsKey(requestId)){ + Thread.sleep(200); + }else { + break; + } + } + Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); + destroyService(); + } + + @Test + public void test_Ex_OnReturn() throws Exception { + initOrResetUrl(true); + initImplicitCallBackURL_onlyOnreturn(); + + destroyService(); + exportExService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(null, ret); + for (int i = 0; i < 10; i++) { + if (! notify.errors.containsKey(requestId)){ + Thread.sleep(200); + }else { + break; + } + } + Assert.assertTrue(! notify.errors.containsKey(requestId)); + destroyService(); + } + + @Test + public void test_Ex_OnInvoke() throws Exception { + initOrResetUrl(true); + initImplicitCallBackURL_onlyOninvoke(); + + destroyService(); + exportExService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(null, ret); + for (int i = 0; i < 10; i++) { + if (! notify.inv.contains(requestId)){ + Thread.sleep(200); + }else { + break; + } + } + Assert.assertTrue(notify.inv.contains(requestId)); + destroyService(); + } + + @Test + public void test_Ex_Onthrow() throws Exception { + initOrResetUrl(true); + initImplicitCallBackURL_onlyOnthrow(); + + destroyService(); + exportExService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(null, ret); + for (int i = 0; i < 10; i++) { + if (! notify.errors.containsKey(requestId)){ + Thread.sleep(200); + }else { + break; + } + } + Assert.assertTrue(notify.errors.containsKey(requestId)); + Assert.assertTrue(notify.errors.get(requestId) instanceof Throwable); + destroyService(); + } + + @Test + public void test_Sync_NoFuture() throws Exception { + initOrResetUrl(false); + initImplicitCallBackURL_onlyOnreturn(); + destroyService(); + exportService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(requestId, ret.getId()); + Future pFuture = RpcContext.getContext().getFuture(); + Assert.assertEquals(null, pFuture); + destroyService(); + } + + @Test + public void test_Async_Future() throws Exception { + initOrResetUrl(true); + destroyService(); + exportService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(null, ret); + Future pFuture = RpcContext.getContext().getFuture(); + ret = pFuture.get(1000, TimeUnit.MICROSECONDS); + Assert.assertEquals(requestId, ret.getId()); + destroyService(); + } + + @Test + public void test_Async_Future_Multi() throws Exception { + initOrResetUrl(true); + destroyService(); + exportService(); + referService(); + + int requestId1 = 1; + Person ret = demoProxy.get(requestId1); + Assert.assertEquals(null, ret); + Future p1Future = RpcContext.getContext().getFuture(); + + int requestId2 = 1; + Person ret2 = demoProxy.get(requestId2); + Assert.assertEquals(null, ret2); + Future p2Future = RpcContext.getContext().getFuture(); + + ret = p1Future.get(1000, TimeUnit.MICROSECONDS); + ret2 = p2Future.get(1000, TimeUnit.MICROSECONDS); + Assert.assertEquals(requestId1, ret.getId()); + Assert.assertEquals(requestId2, ret.getId()); + destroyService(); + } + + @Test(expected = RuntimeException.class) + public void test_Async_Future_Ex() throws Exception { + try{ + initOrResetUrl(true); + destroyService(); + exportExService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(null, ret); + Future pFuture = RpcContext.getContext().getFuture(); + ret = pFuture.get(1000, TimeUnit.MICROSECONDS); + Assert.assertEquals(requestId, ret.getId()); + }finally{ + destroyService(); + } + } + + @Test(expected = RuntimeException.class) + public void test_Normal_Ex() throws Exception { + initOrResetUrl(false); + destroyService(); + exportExService(); + referService(); + + int requestId = 2; + Person ret = demoProxy.get(requestId); + Assert.assertEquals(requestId, ret.getId()); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/dubbo/DubboLazyConnectTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/dubbo/DubboLazyConnectTest.java new file mode 100644 index 0000000000..bf41022b54 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/dubbo/DubboLazyConnectTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.dubbo; + + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.ProtocolUtils; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; + +/** + * dubbo protocol lazy connect test + * @author chao.liuc + * + */ +public class DubboLazyConnectTest { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @Test(expected = RpcException.class) + public void testSticky1(){ + URL url = URL.valueOf("dubbo://127.0.0.1:9090/hi"); + ProtocolUtils.refer(IDemoService.class, url); + } + + @Test + public void testSticky2(){ + URL url = URL.valueOf("dubbo://127.0.0.1:9090/hi?"+RpcConstants.LAZY_CONNECT_KEY+"=true"); + ProtocolUtils.refer(IDemoService.class, url); + } + + @Test(expected = RpcException.class) + public void testSticky3() { + URL url = URL.valueOf("dubbo://127.0.0.1:9090/hi?"+RpcConstants.LAZY_CONNECT_KEY+"=true"); + IDemoService service = (IDemoService)ProtocolUtils.refer(IDemoService.class, url); + service.get(); + } + + @Test + public void testSticky4() { + int port = NetUtils.getAvailablePort(); + URL url = URL.valueOf("dubbo://127.0.0.1:"+port+"/hi?"+RpcConstants.LAZY_CONNECT_KEY+"=true"); + + ProtocolUtils.export(new DemoServiceImpl(), IDemoService.class, url); + + IDemoService service = (IDemoService)ProtocolUtils.refer(IDemoService.class, url); + Assert.assertEquals("ok", service.get()); + } + + public interface IDemoService{ + public String get(); + } + public class DemoServiceImpl implements IDemoService{ + public String get(){ + return "ok"; + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/AccessLogFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/AccessLogFilterTest.java new file mode 100644 index 0000000000..06571d7d87 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/AccessLogFilterTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.LogUtil; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.support.MockInvocation; +import com.alibaba.dubbo.rpc.support.MockInvoker; + +/** + * AccessLogFilterTest.java + * + * @author tony.chenl + */ +public class AccessLogFilterTest { + + Filter accessLogFilter = new AccessLogFilter(); + + // 测试filter不会抛出异常 + @Test + public void testInvokeException() { + Invoker invoker = new MockInvoker(null); + Invocation invocation = new MockInvocation(); + LogUtil.start(); + accessLogFilter.invoke(invoker, invocation); + assertEquals(1, LogUtil.findMessage("Exception in AcessLogFilter of service")); + LogUtil.stop(); + } + + // TODO how to assert thread action + @Test + public void testDefault() { + URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1"); + Invoker invoker = new MockInvoker(url); + Invocation invocation = new MockInvocation(); + accessLogFilter.invoke(invoker, invocation); + } + + @Test + public void testCustom() { + URL url = URL.valueOf("test://test:11/test?accesslog=alibaba"); + Invoker invoker = new MockInvoker(url); + Invocation invocation = new MockInvocation(); + accessLogFilter.invoke(invoker, invocation); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java new file mode 100644 index 0000000000..30b2ddf2f3 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ActiveLimitFilterTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertNotSame; + +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.support.MockInvocation; +import com.alibaba.dubbo.rpc.support.MockInvoker; + +/** + * ActiveLimitFilterTest.java + * + * @author tony.chenl + */ +public class ActiveLimitFilterTest { + + Filter activeLimitFilter = new ActiveLimitFilter(); + private static volatile int count = 0; + + @Test + public void testInvokeNoActives() { + URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&actives=0"); + Invoker invoker = new MockInvoker(url); + Invocation invocation = new MockInvocation(); + activeLimitFilter.invoke(invoker, invocation); + } + + @Test + public void testInvokeLessActives() { + URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&actives=10"); + Invoker invoker = new MockInvoker(url); + Invocation invocation = new MockInvocation(); + activeLimitFilter.invoke(invoker, invocation); + } + + @Test + public void testInvokeGreaterActives() { + URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&actives=1&timeout=1"); + final Invoker invoker = new MockInvoker(url); + final Invocation invocation = new MockInvocation(); + for (int i = 0; i < 100; i++) { + Thread thread = new Thread(new Runnable() { + + public void run() { + for (int i = 0; i < 100; i++) { + try { + activeLimitFilter.invoke(invoker, invocation); + } catch (RpcException expected) { + count++; + } + } + } + }); + thread.start(); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + assertNotSame(0, count); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/CompatibleFilterFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/CompatibleFilterFilterTest.java new file mode 100644 index 0000000000..c4ec681734 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/CompatibleFilterFilterTest.java @@ -0,0 +1,170 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.support.DemoService; +import com.alibaba.dubbo.rpc.support.Type; + +/** + * CompatibleFilterTest.java + * + * @author tony.chenl + */ +public class CompatibleFilterFilterTest { + + Filter compatibleFilter = new CompatibleFilter(); + Invocation invocation; + Invoker invoker; + + @After + public void tearDown() { + EasyMock.reset(invocation, invoker); + } + + @Test + public void testInvokerGeneric() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("$enumlength").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = compatibleFilter.invoke(invoker, invocation); + assertEquals(filterResult, result); + } + + @Test + public void testResulthasException() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("enumlength").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setException(new RuntimeException()); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = compatibleFilter.invoke(invoker, invocation); + assertEquals(filterResult, result); + } + + @Test + public void testInvokerJsonPojoSerialization() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("enumlength").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Type[].class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1&serialization=json"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = compatibleFilter.invoke(invoker, invocation); + assertEquals(Type.High, filterResult.getResult()); + } + + @Test + public void testInvokerNonJsonEnumSerialization() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("enumlength").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Type[].class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = compatibleFilter.invoke(invoker, invocation); + assertEquals(Type.High, filterResult.getResult()); + } + + @Test + public void testInvokerNonJsonNonPojoSerialization() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("echo").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] {String.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult(new String[]{"High"}); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = compatibleFilter.invoke(invoker, invocation); + assertArrayEquals(new String[]{"High"}, (String[])filterResult.getResult()); + } + + @Test + public void testInvokerNonJsonPojoSerialization() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("echo").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { String.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("hello"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = compatibleFilter.invoke(invoker, invocation); + assertEquals("hello", filterResult.getResult()); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilterTest.java new file mode 100644 index 0000000000..5d861fc802 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilterTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.support.DemoService; +import com.alibaba.dubbo.rpc.support.MockInvocation; +import com.alibaba.dubbo.rpc.support.MockInvoker; + +/** + * ConsumerContextFilterTest.java + * @author tony.chenl + */ +public class ConsumerContextFilterTest { + Filter consumerContextFilter = new ConsumerContextFilter(); + @Test + public void testSetContext(){ + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + Invoker invoker = new MockInvoker(url); + Invocation invocation = new MockInvocation(); + consumerContextFilter.invoke(invoker, invocation); + assertEquals(invoker,RpcContext.getContext().getInvoker()); + assertEquals(invocation,RpcContext.getContext().getInvocation()); + assertEquals(NetUtils.getLocalHost() + ":0",RpcContext.getContext().getLocalAddressString()); + assertEquals("test:11",RpcContext.getContext().getRemoteAddressString()); + + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ContextFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ContextFilterTest.java new file mode 100644 index 0000000000..c10c801b50 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/ContextFilterTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertNull; + +import org.easymock.EasyMock; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.support.DemoService; +import com.alibaba.dubbo.rpc.support.MockInvocation; +import com.alibaba.dubbo.rpc.support.MockInvoker; + +/** + * ContextFilterTest.java + * TODO 增强断言 + * @author tony.chenl + */ +public class ContextFilterTest { + + Filter contextFilter = new ContextFilter(); + Invoker invoker; + Invocation invocation; + + @SuppressWarnings("unchecked") + @Test + public void testSetContext() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("$enumlength").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.expect(invocation.getAttachments()).andReturn(null).anyTimes(); + EasyMock.replay(invocation); + invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + contextFilter.invoke(invoker, invocation); + assertNull(RpcContext.getContext().getInvoker()); + } + + @Test + public void testWithAttachments() { + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + Invoker invoker = new MockInvoker(url); + Invocation invocation = new MockInvocation(); + Result result = contextFilter.invoke(invoker, invocation); + assertNull(RpcContext.getContext().getInvoker()); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/DeprecatedFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/DeprecatedFilterTest.java new file mode 100644 index 0000000000..81cba999e2 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/DeprecatedFilterTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.LogUtil; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.support.DemoService; +import com.alibaba.dubbo.rpc.support.MockInvocation; +import com.alibaba.dubbo.rpc.support.MockInvoker; + +/** + * DeprecatedFilterTest.java + * + * @author tony.chenl + */ +public class DeprecatedFilterTest { + + Filter deprecatedFilter = new DeprecatedFilter(); + + @Test + public void testDeprecatedFilter() { + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1&echo." + Constants.DEPRECATED_KEY + "=true"); + LogUtil.start(); + deprecatedFilter.invoke(new MockInvoker(url), new MockInvocation()); + assertEquals(1, + LogUtil.findMessage("The service method com.alibaba.dubbo.rpc.support.DemoService.echo(String) is DEPRECATED")); + LogUtil.stop(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/EchoFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/EchoFilterTest.java new file mode 100644 index 0000000000..00351d18c2 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/EchoFilterTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertEquals; + +import org.easymock.EasyMock; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.support.DemoService; + +/** + * EchoFilterTest.java + * + * @author tony.chenl + */ +public class EchoFilterTest { + + Filter echoFilter = new EchoFilter(); + + @SuppressWarnings("unchecked") + @Test + public void testEcho() { + Invocation invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("$echo").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.expect(invocation.getAttachments()).andReturn(null).anyTimes(); + EasyMock.replay(invocation); + Invoker invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = echoFilter.invoke(invoker, invocation); + assertEquals("hello", filterResult.getResult()); + } + + @SuppressWarnings("unchecked") + @Test + public void testNonEcho() { + Invocation invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("echo").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.expect(invocation.getAttachments()).andReturn(null).anyTimes(); + EasyMock.replay(invocation); + Invoker invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = echoFilter.invoke(invoker, invocation); + assertEquals("High", filterResult.getResult()); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/EventFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/EventFilterTest.java new file mode 100644 index 0000000000..e64a9fa1a8 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/filter/EventFilterTest.java @@ -0,0 +1,89 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.easymock.EasyMock; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.support.DemoService; + +/** + * EventFilterTest.java + * + * @author tony.chenl + * TODO 暂时依赖callback集成测试,后续补充 + */ +public class EventFilterTest { + Filter eventFilter = new EventFilter(); + private static Invocation invocation; + + @BeforeClass + public static void setUp() { + invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("echo").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.expect(invocation.getAttachments()).andReturn(null).anyTimes(); + EasyMock.replay(invocation); + } + + @Test + public void testSyncCallback() { + Invoker invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setResult("High"); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + Result filterResult = eventFilter.invoke(invoker, invocation); + assertEquals("High", filterResult.getResult()); + } + + @Test(expected = RuntimeException.class) + public void testSyncCallbackHasException() throws RpcException, Throwable { + Invocation invocation = EasyMock.createMock(Invocation.class); + EasyMock.expect(invocation.getMethodName()).andReturn("echo").anyTimes(); + EasyMock.expect(invocation.getParameterTypes()).andReturn(new Class[] { Enum.class }).anyTimes(); + EasyMock.expect(invocation.getArguments()).andReturn(new Object[] { "hello" }).anyTimes(); + EasyMock.expect(invocation.getAttachments()).andReturn(null).anyTimes(); + EasyMock.replay(invocation); + Invoker invoker = EasyMock.createMock(Invoker.class); + EasyMock.expect(invoker.isAvailable()).andReturn(true).anyTimes(); + EasyMock.expect(invoker.getInterface()).andReturn(DemoService.class).anyTimes(); + RpcResult result = new RpcResult(); + result.setException(new RuntimeException()); + EasyMock.expect(invoker.invoke(invocation)).andReturn(result).anyTimes(); + URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1&"+RpcConstants.ON_THROW_METHOD_KEY+"=echo"); + EasyMock.expect(invoker.getUrl()).andReturn(url).anyTimes(); + EasyMock.replay(invoker); + eventFilter.invoke(invoker, invocation).recreate(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/generic/EnumBak.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/generic/EnumBak.java new file mode 100644 index 0000000000..cf797e0df0 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/generic/EnumBak.java @@ -0,0 +1,190 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.generic; + + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.proxy.ProxyFactory; +import com.alibaba.dubbo.rpc.service.GenericService; +import com.alibaba.dubbo.rpc.support.DemoService; +import com.alibaba.dubbo.rpc.support.DemoServiceImpl; +import com.alibaba.dubbo.rpc.support.Type; + +public class EnumBak { + + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + @Test + public void testNormal(){ + int port = NetUtils.getAvailablePort(); + URL serviceurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?proxy=jdk" + + "&service.interface=com.alibaba.dubbo.rpc.DemoService" + + "&reference.filter=compatible" + + "&timeout="+Integer.MAX_VALUE + ); + DemoService demo = new DemoServiceImpl(); + Invoker invoker = proxy.getInvoker(demo, DemoService.class, serviceurl); + protocol.export(invoker); + + URL consumerurl = serviceurl; + Invoker reference = protocol.refer(DemoService.class, consumerurl); + DemoService demoProxy = (DemoService)proxy.getProxy(reference); +// System.out.println(demoProxy.getThreadName()); + System.out.println("byte:"+demoProxy.getbyte((byte)-128)); + +// invoker.destroy(); + reference.destroy(); + } + @Ignore + @Test + public void testExportService() throws InterruptedException{ + int port = NetUtils.getAvailablePort(); + URL serviceurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?proxy=jdk&timeout="+Integer.MAX_VALUE + ); + DemoService demo = new DemoServiceImpl(); + Invoker invoker = proxy.getInvoker(demo, DemoService.class, serviceurl); + protocol.export(invoker); + synchronized (EnumBak.class) { + EnumBak.class.wait(); + } + +// URL consumerurl = serviceurl; +// Invoker reference = protocol.refer(DemoService.class, consumerurl); +// DemoService demoProxy = (DemoService)proxyFactory.createProxy(reference); +//// System.out.println(demoProxy.getThreadName()); +// System.out.println("byte:"+demoProxy.getbyte((byte)-128)); +// +// invoker.destroy(); +// reference.destroy(); + } + + @Test + public void testNormalEnum(){ + int port = NetUtils.getAvailablePort(); + URL serviceurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?timeout="+Integer.MAX_VALUE + ); + DemoService demo = new DemoServiceImpl(); + Invoker invoker = proxy.getInvoker(demo, DemoService.class, serviceurl); + protocol.export(invoker); + + URL consumerurl = serviceurl; + Invoker reference = protocol.refer(DemoService.class, consumerurl); + DemoService demoProxy = (DemoService)proxy.getProxy(reference); + Type type = demoProxy.enumlength(Type.High); + System.out.println(type); + Assert.assertEquals(Type.High, type); + + invoker.destroy(); + reference.destroy(); + } +// @Test + //测试2.0.5调用2.0.3的兼容 + public void testEnumCompat(){ + int port = 20880; + URL consumerurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?timeout="+Integer.MAX_VALUE + ); + Invoker reference = protocol.refer(DemoService.class, consumerurl); + DemoService demoProxy = (DemoService)proxy.getProxy(reference); + Type type = demoProxy.enumlength(Type.High); + System.out.println(type); + Assert.assertEquals(Type.High, type); + reference.destroy(); + } +// @Test + //测试2.0.5调用2.0.3的兼容 + public void testGenricEnumCompat(){ + int port = 20880; + URL consumerurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?timeout="+Integer.MAX_VALUE + ); + Invoker reference = protocol.refer(GenericService.class, consumerurl); + + GenericService demoProxy = (GenericService)proxy.getProxy(reference); + Object obj = demoProxy.$invoke("enumlength", new String[]{Type[].class.getName()}, new Object[]{new Type[]{Type.High,Type.High}}); + System.out.println("obj---------->"+obj); + reference.destroy(); + } + +// @Test + //测试2.0.5调用2.0.3的兼容 自定义类型参数中包含enum类型 + public void testGenricCustomArg(){ + + int port = 20880; + URL consumerurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?timeout=2000000" + ); + Invoker reference = protocol.refer(GenericService.class, consumerurl); + + GenericService demoProxy = (GenericService)proxy.getProxy(reference); + Map arg = new HashMap(); + arg.put("type", "High"); + arg.put("name", "hi"); + + Object obj = demoProxy.$invoke("get", new String[]{"com.alibaba.dubbo.rpc.CustomArgument"}, new Object[]{arg}); + System.out.println("obj---------->"+obj); + reference.destroy(); + } + +// @Ignore +// @Test + public void testGenericExport() throws InterruptedException{ + int port = NetUtils.getAvailablePort(); + port = 20880; + URL serviceurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?timeout="+Integer.MAX_VALUE + + "&"+Constants.SERVICE_FILTER_KEY+"=ready,context,token,exception,echo,generic,accesslog,trace,classloader,executelimit,timeout" + ); + DemoService demo = new DemoServiceImpl(); + Invoker invoker = proxy.getInvoker(demo, DemoService.class, serviceurl); + protocol.export(invoker); + + + //SERVER + Thread.sleep(Integer.MAX_VALUE); + } + + @Test + public void testGenericEnum() throws InterruptedException{ + int port = NetUtils.getAvailablePort(); + URL serviceurl = URL.valueOf("dubbo://127.0.0.1:"+port+"/test?timeout="+Integer.MAX_VALUE + + "&"+Constants.SERVICE_FILTER_KEY+"=ready,context,token,exception,echo,generic,accesslog,trace,classloader,executelimit,timeout" + ); + DemoService demo = new DemoServiceImpl(); + Invoker invoker = proxy.getInvoker(demo, DemoService.class, serviceurl); + protocol.export(invoker); + + URL consumerurl = serviceurl.addParameter(Constants.REFERENCE_FILTER_KEY, "consumercontext,compatible,deprecated,genericimpl,activelimit"); + + Invoker reference = protocol.refer(GenericService.class, consumerurl); + + GenericService demoProxy = (GenericService)proxy.getProxy(reference); + Object obj = demoProxy.$invoke("enumlength", new String[]{Type[].class.getName()}, new Object[]{new Type[]{Type.High,Type.High}}); + System.out.println("obj---------->"+obj); + + invoker.destroy(); + reference.destroy(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoRequest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoRequest.java new file mode 100644 index 0000000000..f6f1e42b3b --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoRequest.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import java.io.Serializable; + +/** + * TestRequest. + * + * @author qian.lei + */ + +class DemoRequest implements Serializable +{ + private static final long serialVersionUID = -2579095288792344869L; + + private String mServiceName; + + private String mMethodName; + + private Class[] mParameterTypes; + + private Object[] mArguments; + + public DemoRequest(String serviceName,String methodName, Class[] parameterTypes,Object[] args) + { + mServiceName = serviceName; + mMethodName = methodName; + mParameterTypes = parameterTypes; + mArguments = args; + } + + public String getServiceName() + { + return mServiceName; + } + + public String getMethodName() + { + return mMethodName; + } + + public Class[] getParameterTypes() { + return mParameterTypes; + } + + public Object[] getArguments() + { + return mArguments; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoRpcProtocol.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoRpcProtocol.java new file mode 100644 index 0000000000..cf7db4f636 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoRpcProtocol.java @@ -0,0 +1,160 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.Extension; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; +import com.alibaba.dubbo.remoting.exchange.ExchangeServer; +import com.alibaba.dubbo.remoting.exchange.Exchangers; +import com.alibaba.dubbo.remoting.exchange.support.Replier; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.support.AbstractExporter; +import com.alibaba.dubbo.rpc.support.AbstractInvoker; +import com.alibaba.dubbo.rpc.support.AbstractProtocol; + +/** + * TestProtocolSupport. + * + * @author qian.lei + */ +@Extension("demo") +public class DemoRpcProtocol extends AbstractProtocol { + + private final Map mClientMap = new HashMap(); // + + private final Map mServerMap = new HashMap(); // + + private final Map> mServiceMap = new HashMap>(); // + + private final Replier mHandler = new InternalHandler(); + + public int getDefaultPort() { + return 123456; + } + + public Invoker refer(Class serviceType, URL url) throws RpcException + { + ExchangeChannel client = mClientMap.get(url.getHost() + ':' + url.getPort()); + if( client == null ) + { + // create client. + try { + client = Exchangers.connect(url); + } catch (RemotingException e) { + throw new RpcException(e.getMessage(), e); + } + mClientMap.put(url.getHost() + ':' + url.getPort(),client); + } + final ExchangeChannel fc = client; + return new AbstractInvoker(serviceType, url){ + public Object doInvoke(Invocation invocation) throws Throwable + { + DemoRequest req = new DemoRequest(getUrl().getPath(), invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); + int timeout = getUrl().getMethodIntParameter(invocation.getMethodName(), "timeout"); + if( timeout > 0 ) + return fc.request(req, timeout).get(); + return fc.request(req).get(); + } + }; + } + + public Exporter export(Invoker invoker) throws RpcException { + URL url = invoker.getUrl(); + if( !mServerMap.containsKey(url.getPort()) ) + { + ExchangeServer server; + try { + server = Exchangers.bind(url, mHandler); + } catch (RemotingException e) { + throw new RpcException(e.getMessage(), e); + } + mServerMap.put(url.getPort(),server); + } + InternalExporter exporter = new InternalExporter(invoker); + mServiceMap.put(url.getPath()+'@'+url.getPort(), exporter); + return exporter; + } + + public void destroy() + { + for (String key : new ArrayList(mServiceMap.keySet())) { + InternalExporter exporter = mServiceMap.remove(key); + if (exporter != null) { + try { + exporter.unexport(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + for (Integer key : new ArrayList(mServerMap.keySet())) { + ExchangeServer server = mServerMap.remove(key); + if (server != null) { + try { + server.close(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + for (String key : new ArrayList(mClientMap.keySet())) { + ExchangeChannel client = mClientMap.remove(key); + if (client != null) { + try { + client.close(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } + } + } + + private static class InternalExporter extends AbstractExporter + { + public InternalExporter(Invoker invoker) + { + super(invoker); + } + } + + private class InternalHandler implements Replier { + public Object reply(ExchangeChannel channel, DemoRequest msg) throws RemotingException { + // find service instance. + int port = channel.getLocalAddress().getPort(); + String serviceName = msg.getServiceName(); + InternalExporter exporter = mServiceMap.get(serviceName+'@'+port); + if( exporter == null ) + throw new RemotingException(channel, "Service " + serviceName + " not found."); + try { + return exporter.invoke(new RpcInvocation(msg.getMethodName(), msg.getParameterTypes(), msg.getArguments()), channel.getRemoteAddress()).recreate(); + } catch (RpcException e) { + throw new RemotingException(channel, e.getMessage(), e); + } catch (Throwable e) { + throw new RemotingException(channel, e.getMessage(), e); + } + } + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoService.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoService.java new file mode 100644 index 0000000000..7e4dfb93a7 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoService.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +/** + * TestService + */ + +public interface DemoService +{ + void sayHello(String name); + + String echo(String text); + + long timestamp(); + + String getThreadName(); + + int getSize(String[] strs); + + int getSize(Object[] os); + + Object invoke(String service, String method) throws Exception; + + int stringLength(String str); + + Type enumlength(Type... types); +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoServiceImpl.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoServiceImpl.java new file mode 100644 index 0000000000..7b872500af --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/DemoServiceImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * DemoServiceImpl + */ + +public class DemoServiceImpl implements DemoService +{ + public DemoServiceImpl() + { + super(); + } + + public void sayHello(String name) { + System.out.println("hello "+name); + } + + public String echo(String text) + { + return text; + } + + public long timestamp() { + return System.currentTimeMillis(); + } + + public String getThreadName() + { + return Thread.currentThread().getName(); + } + + public int getSize(String[] strs) + { + if( strs == null ) + return -1; + return strs.length; + } + + public int getSize(Object[] os) + { + if( os == null ) + return -1; + return os.length; + } + + public Object invoke(String service, String method) throws Exception + { + System.out.println("RpcContext.getContext().getRemoteHost()="+RpcContext.getContext().getRemoteHost()); + return service + ":" + method; + } + + public Type enumlength(Type... types) + { + if( types.length == 0 ) + return Type.Lower; + return types[0]; + } + + public int stringLength(String str) + { + return str.length(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/MultiThreadTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/MultiThreadTest.java new file mode 100644 index 0000000000..5f7bb22cee --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/MultiThreadTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.TestCase; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Exporter; +import com.alibaba.dubbo.rpc.Protocol; + +public class MultiThreadTest extends TestCase +{ + + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + public void testDubboMultiThreadInvoke() throws Exception + { + Exporter rpcExporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, URL.valueOf("dubbo://127.0.0.1:20880/TestService"))); + + final AtomicInteger counter = new AtomicInteger(); + final DemoService service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:20880/TestService"))); + assertEquals(service.getSize(new String[]{"123", "456", "789"}), 3); + + final StringBuffer sb = new StringBuffer(); + for(int i=0;i<1024*64+32;i++) + sb.append('A'); + assertEquals(sb.toString(), service.echo(sb.toString())); + + ExecutorService exec = Executors.newFixedThreadPool(10); + for(int i=0;i<10;i++) + { + final int fi = i; + exec.execute(new Runnable(){ + public void run() + { + for(int i=0;i<30;i++) + { + System.out.println(fi+":"+counter.getAndIncrement()); + assertEquals(service.echo(sb.toString()), sb.toString()); + } + } + }); + } + exec.shutdown(); + exec.awaitTermination(10, TimeUnit.SECONDS); + rpcExporter.unexport(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/ProtocolsTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/ProtocolsTest.java new file mode 100644 index 0000000000..2fef144b7a --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/ProtocolsTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + + +import static junit.framework.Assert.assertEquals; + +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.service.EchoService; + +/** + * ProxiesTest + */ + +public class ProtocolsTest +{ + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + @Test + public void testDemoProtocol() throws Exception + { + DemoService service = new DemoServiceImpl(); + protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:9020/TestService?codec=exchange"))); + service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:9020/TestService?codec=exchange"))); + assertEquals(service.getSize(new String[]{"", "", ""}), 3); + } + + @Test + public void testLocalProtocol() throws Exception + { + DemoService service = new DemoServiceImpl(); + protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("injvm://127.0.0.1/TestService"))); + service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("injvm://127.0.0.1/TestService"))); + assertEquals(service.getSize(new String[]{"", "", ""}), 3); + service.invoke("injvm://127.0.0.1/TestService", "invoke"); + } + + @Test + public void testDubboProtocol() throws Exception + { + DemoService service = new DemoServiceImpl(); + protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:9010/TestService?service.filter=echo"))); + service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:9010/TestService"))); + assertEquals(service.enumlength(new Type[]{}), Type.Lower); + assertEquals(service.getSize(null), -1); + assertEquals(service.getSize(new String[]{"", "", ""}), 3); + service.invoke("dubbo://127.0.0.1:9010/TestService", "invoke"); + + service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:9010/TestService?client=netty"))); + // test netty client + StringBuffer buf = new StringBuffer(); + for(int i=0;i<1024*32+32;i++) + buf.append('A'); + System.out.println(service.stringLength(buf.toString())); + + // cast to EchoService + EchoService echo = proxy.getProxy(protocol.refer(EchoService.class, URL.valueOf("dubbo://127.0.0.1:9010/TestService?client=netty"))); + assertEquals(echo.$echo(buf.toString()), buf.toString()); + assertEquals(echo.$echo("test"), "test"); + assertEquals(echo.$echo("abcdefg"), "abcdefg"); + assertEquals(echo.$echo(1234), 1234); + } + + @Test + public void testPerm() throws Exception + { + DemoService service = new DemoServiceImpl(); + protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:9050/TestService?codec=exchange"))); + service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:9050/TestService?codec=exchange"))); + long start = System.currentTimeMillis(); + for(int i=0;i<1000;i++) + service.getSize(new String[]{"", "", ""}); + System.out.println("take:"+(System.currentTimeMillis()-start)); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RemoteService.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RemoteService.java new file mode 100644 index 0000000000..b04a2d3c37 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RemoteService.java @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +public interface RemoteService extends Remote +{ + String sayHello(String name) throws RemoteException; + + String getThreadName() throws RemoteException; +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RemoteServiceImpl.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RemoteServiceImpl.java new file mode 100644 index 0000000000..76cc115ff8 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RemoteServiceImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import java.rmi.RemoteException; + +import com.alibaba.dubbo.rpc.RpcContext; + +public class RemoteServiceImpl implements RemoteService +{ + public String getThreadName() throws RemoteException + { + System.out.println("RpcContext.getContext().getRemoteHost()="+RpcContext.getContext().getRemoteHost()); + return Thread.currentThread().getName(); + } + + public String sayHello(String name) throws RemoteException + { + return "hello " + name + "@" + RemoteServiceImpl.class.getName(); + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RpcFilterTest.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RpcFilterTest.java new file mode 100644 index 0000000000..5941363779 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/RpcFilterTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +import junit.framework.TestCase; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.service.EchoService; + +public class RpcFilterTest extends TestCase +{ + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + public void testRpcFilter() throws Exception + { + DemoService service = new DemoServiceImpl(); + URL url = URL.valueOf("dubbo://127.0.0.1:9010/com.alibaba.dubbo.rpc.DemoService?service.filter=echo"); + protocol.export(proxy.getInvoker(service, DemoService.class, url)); + service = proxy.getProxy(protocol.refer(DemoService.class, url)); + assertEquals("123",service.echo("123")); + // cast to EchoService + EchoService echo = proxy.getProxy(protocol.refer(EchoService.class, url)); + assertEquals(echo.$echo("test"), "test"); + assertEquals(echo.$echo("abcdefg"), "abcdefg"); + assertEquals(echo.$echo(1234), 1234); + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/Type.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/Type.java new file mode 100644 index 0000000000..314c1402d7 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/proxy/Type.java @@ -0,0 +1,21 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.proxy; + +public enum Type +{ + High, Normal, Lower +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/DemoService.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/DemoService.java new file mode 100644 index 0000000000..f191ae8ed7 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/DemoService.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import com.alibaba.dubbo.rpc.CustomArgument; + + +/** + * TestService + */ + +public interface DemoService +{ + void sayHello(String name); + + String echo(String text); + + long timestamp(); + + String getThreadName(); + + int getSize(String[] strs); + + int getSize(Object[] os); + + Object invoke(String service, String method) throws Exception; + + int stringLength(String str); + + Type enumlength(Type... types); + +// Type enumlength(Type type); + + String get(CustomArgument arg1); + + byte getbyte(byte arg); + +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/DemoServiceImpl.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/DemoServiceImpl.java new file mode 100644 index 0000000000..8b602eec60 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/DemoServiceImpl.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import com.alibaba.dubbo.rpc.CustomArgument; +import com.alibaba.dubbo.rpc.RpcContext; + +/** + * DemoServiceImpl + */ + +public class DemoServiceImpl implements DemoService +{ + public DemoServiceImpl() + { + super(); + } + + public void sayHello(String name) { + System.out.println("hello "+name); + } + + public String echo(String text) + { + return text; + } + + public long timestamp() { + return System.currentTimeMillis(); + } + + public String getThreadName() + { + return Thread.currentThread().getName(); + } + + public int getSize(String[] strs) + { + if( strs == null ) + return -1; + return strs.length; + } + + public int getSize(Object[] os) + { + if( os == null ) + return -1; + return os.length; + } + + public Object invoke(String service, String method) throws Exception + { + System.out.println("RpcContext.getContext().getRemoteHost()="+RpcContext.getContext().getRemoteHost()); + return service + ":" + method; + } + + public Type enumlength(Type... types) + { + if( types.length == 0 ) + return Type.Lower; + return types[0]; + } + + public Type enumlength(Type type) + { + return type; + } + + public int stringLength(String str) + { + return str.length(); + } + public String get(CustomArgument arg1){ + return arg1.toString(); + } + + public byte getbyte(byte arg) { + return arg; + } + + public Person gerPerson(Person person) { + return person; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/IEcho.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/IEcho.java new file mode 100644 index 0000000000..96a916fe82 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/IEcho.java @@ -0,0 +1,20 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +public interface IEcho { + String echo(String e); +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java new file mode 100644 index 0000000000..0cf791d5fe --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.rpc.Invocation; + +/** + * MockInvocation.java + * + * @author tony.chenl + */ +public class MockInvocation implements Invocation { + + public String getMethodName() { + return "echo"; + } + + public Class[] getParameterTypes() { + return new Class[] { String.class }; + } + + public Object[] getArguments() { + return new Object[] { "aa" }; + } + + public Map getAttachments() { + Map attachments = new HashMap(); + attachments.put(Constants.PATH_KEY, "dubbo"); + attachments.put(Constants.GROUP_KEY, "dubbo"); + attachments.put(Constants.VERSION_KEY, "1.0.0"); + attachments.put(Constants.DUBBO_VERSION_KEY, "1.0.0"); + attachments.put(Constants.TOKEN_KEY, "sfag"); + attachments.put(Constants.TIMEOUT_KEY, "1000"); + return attachments; + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/MockInvoker.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/MockInvoker.java new file mode 100644 index 0000000000..21c31714c1 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/MockInvoker.java @@ -0,0 +1,74 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; + +/** + * MockInvoker.java + * + * @author tony.chenl + */ +public class MockInvoker implements Invoker { + + URL url; + Class type; + boolean hasException = false; + + public MockInvoker(URL url){ + this.url = url; + type = (Class) DemoService.class; + } + + public MockInvoker(URL url, boolean hasException){ + this.url = url; + type = (Class) DemoService.class; + this.hasException = hasException; + } + + public Class getInterface() { + return type; + } + + public URL getUrl() { + return url; + } + + public boolean isAvailable() { + return false; + } + + public Result invoke(Invocation invocation) throws RpcException { + RpcResult result = new RpcResult(); + if (hasException == false) { + result.setResult("alibaba"); + return result; + } else { + result.setException(new RuntimeException("mocked exception")); + return result; + } + + } + + public void destroy() { + } + +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/Person.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/Person.java new file mode 100644 index 0000000000..19db863169 --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/Person.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +import java.io.Serializable; + +/** + * Person.java + * + * @author tony.chenl + */ +public class Person implements Serializable { + + private static final long serialVersionUID = 1L; + private String name; + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/Type.java b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/Type.java new file mode 100644 index 0000000000..ed1dd9a50c --- /dev/null +++ b/dubbo-rpc/src/test/java/com/alibaba/dubbo/rpc/support/Type.java @@ -0,0 +1,21 @@ +/* + * Copyright 1999-2011 Alibaba Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 com.alibaba.dubbo.rpc.support; + +public enum Type +{ + High, Normal, Lower +} \ No newline at end of file diff --git a/dubbo-rpc/src/test/resources/log4j.xml b/dubbo-rpc/src/test/resources/log4j.xml new file mode 100644 index 0000000000..6a79df3ec4 --- /dev/null +++ b/dubbo-rpc/src/test/resources/log4j.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo/pom.xml b/dubbo/pom.xml new file mode 100644 index 0000000000..e7c720a813 --- /dev/null +++ b/dubbo/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + + com.alibaba + dubbo-parent + 2.0.7 + + dubbo + jar + Dubbo All In One + The all in one project of dubbo + + + com.alibaba + dubbo-config + ${project.parent.version} + + + + + + maven-source-plugin + + + attach-sources + none + + + + + org.apache.maven.plugins + maven-shade-plugin + 1.4 + + + package + + shade + + + true + true + + + com.alibaba:dubbo-common + com.alibaba:dubbo-remoting + com.alibaba:dubbo-rpc + com.alibaba:dubbo-cluster + com.alibaba:dubbo-registry + com.alibaba:dubbo-config + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000..6c6ea38665 --- /dev/null +++ b/pom.xml @@ -0,0 +1,347 @@ + + + 4.0.0 + + com.alibaba + opensesame + 1.0 + + dubbo-parent + 2.0.7 + pom + Dubbo Parent POM + The top project of dubbo + + dubbo-common + dubbo-remoting + dubbo-rpc + dubbo-cluster + dubbo-registry + dubbo-monitor + dubbo-config + dubbo-container + dubbo + + + + 2.5.6.SEC03 + 3.15.0-GA + 3.2.5.Final + 1.1.7 + 2.1.4 + 3.2.1 + 1.4.1 + 1.1.6 + 3.1 + + 1.2.16 + 1.6.2 + + 4.10 + 3.0 + 0.999.8 + + -Xms512m -Xmx512m + + http://code.alibabatech.com/wiki/display/dubbo/Home + http://code.alibabatech.com/svn/dubbo/trunk + scm:svn:http://code.alibabatech.com/svn/dubbo/trunk + http://code.alibabatech.com/jira/browse/DUBBO + http://code.alibabatech.com/wiki/display/dubbo/Home + + + + + + org.springframework + spring + ${spring_version} + + + org.javassist + javassist + ${javassist_version} + + + org.jboss.netty + netty + ${netty_version} + + + org.apache.mina + mina-core + ${mina_version} + + + org.glassfish.grizzly + grizzly-core + ${grizzly_version} + + + com.alibaba + hessian.lite + ${hessian_version} + + + com.alibaba + fastjson + ${fastjson_version} + + + com.thoughtworks.xstream + xstream + ${xstream_version} + + + org.apache.bsf + bsf-api + ${bsf_version} + + + + log4j + log4j + ${log4j_version} + + + org.slf4j + slf4j-api + ${slf4j_version} + + + + junit + junit + ${junit_version} + test + + + org.easymock + easymock + ${easymock_version} + test + + + com.googlecode.jmockit + jmockit + ${jmockit_version} + test + + + org.easymock + easymockclassextension + ${easymock_version} + test + + + + + + junit + junit + + + org.easymock + easymock + + + org.easymock + easymockclassextension + + + com.googlecode.jmockit + jmockit + + + + + alibaba-opensource + Alibaba Open Source Repository + http://code.alibabatech.com/mvn/releases + + true + + + false + + + + alibaba-opensource-snapshot + Alibaba Open Source Snapshot Repository + http://code.alibabatech.com/mvn/snapshots + + false + + + true + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + true + true + + true + true + + + ${timestamp} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + pertest + ${argline} + + + + transporter + ${transporter} + + + serialization + ${serialization} + + + + port + ${port} + + + threadpool + ${threadpool} + + + threads + ${threads} + + + iothreads + ${iothreads} + + + + server + ${server} + + + timeout + ${timeout} + + + length + ${length} + + + connections + ${connections} + + + base + ${base} + + + concurrent + ${concurrent} + + + runs + ${runs} + + + onerror + ${onerror} + + + + + + + + ${project_scm_connection} + ${project_scm_connection} + ${project_scm_url} + + + + QianXiao(Shawn) + shawn.qianx + shawn.qianx (AT) alibaba-inc.com + + Developer + + +8 + + + LiangFei(William) + william.liangf + william.liangf (AT) alibaba-inc.com + + Developer + + +8 + + + LiDing(Jerry) + ding.lid + ding.lid (AT) alibaba-inc.com + + Developer + + +8 + + + LiuChao(Charles) + chao.liuc + chao.liuc (AT) alibaba-inc.com + + Developer + + +8 + + + LiuHaoMin(Ludvik) + haoming.liuhm + haoming.liuhm (AT) alibaba-inc.com + + Developer + + +8 + + + ChenLei(Tony) + tony.chenl + tony.chenl (AT) alibaba-inc.com + + Developer + + +8 + + + \ No newline at end of file