Add 2.0.7

git-svn-id: http://code.alibabatech.com/svn/dubbo/trunk@8 1a56cb94-b969-4eaa-88fa-be21384802f2
This commit is contained in:
william.liangf 2011-10-20 15:06:57 +00:00
parent d22223d3bc
commit 10052d4687
669 changed files with 71704 additions and 0 deletions

13
COPYRIGHT Normal file
View File

@ -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.

202
LICENSE Normal file
View File

@ -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.

41
dubbo-cluster/pom.xml Normal file
View File

@ -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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-parent</artifactId>
<version>2.0.7</version>
</parent>
<artifactId>dubbo-cluster</artifactId>
<packaging>jar</packaging>
<name>Dubbo Cluster Module</name>
<description>The cluster module of dubbo project</description>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-rpc</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.bsf</groupId>
<artifactId>bsf-api</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -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)
*
* <a href="http://en.wikipedia.org/wiki/Computer_cluster">Cluster</a>
* <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a>
*
* @author william.liangf
*/
@Extension(FailoverCluster.NAME)
public interface Cluster {
/**
* Merge the directory invokers to a virtual invoker.
*
* @param <T>
* @param directory
* @return
* @throws RpcException
*/
@Adaptive
<T> Invoker<T> merge(Directory<T> directory) throws RpcException;
}

View File

@ -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)
*
* <a href="http://en.wikipedia.org/wiki/Directory_service">Directory Service</a>
*
* @see com.alibaba.dubbo.rpc.cluster.Cluster#merge(Directory)
* @author william.liangf
*/
public interface Directory<T> extends Node {
/**
* get service type.
*
* @return service type.
*/
Class<T> getInterface();
/**
* list invokers.
*
* @return invokers
*/
List<Invoker<T>> list(Invocation invocation) throws RpcException;
}

View File

@ -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)
*
* <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a>
*
* @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.
*/
<T> Invoker<T> select(List<Invoker<T>> invokers, Invocation invocation) throws RpcException;
}

View File

@ -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
*/
<T> List<Invoker<T>> route(List<Invoker<T>> invokers, Invocation invocation) throws RpcException;
}

View File

@ -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);
}

View File

@ -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<T> extends AbstractDirectory<T> {
private final List<Invoker<T>> invokers;
private static final List<Invoker<?>> EMPTY_INVOKERLIST = new ArrayList<Invoker<?>>();
public StaticDirectory(List<Invoker<T>> invokers){
this(null, invokers, null);
}
public StaticDirectory(List<Invoker<T>> invokers, List<Router> routers){
this(null, invokers, routers);
}
public StaticDirectory(URL url, List<Invoker<T>> invokers) {
this(url, invokers, null);
}
public StaticDirectory(URL url, List<Invoker<T>> invokers, List<Router> routers) {
super(url == null && invokers != null && invokers.size() > 0 ? invokers.get(0).getUrl() : url, routers);
if (invokers == null || invokers.size() == 0)
throw new IllegalArgumentException("invokers == null");
this.invokers = invokers;
}
public Class<T> getInterface() {
return invokers.get(0).getInterface();
}
public boolean isAvailable() {
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
return true;
}
}
return false;
}
public void destroy() {
for (Invoker<T> invoker : invokers) {
invoker.destroy();
}
invokers.clear();
}
@Override
protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
return invokers;
}
}

View File

@ -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 <T> Invoker<T> select(List<Invoker<T>> 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 <T> Invoker<T> doSelect(List<Invoker<T>> invokers, Invocation invocation);
protected int getWeight(Invoker<?> invoker, Invocation invocation) {
return invoker.getUrl().getMethodIntParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
}
}

View File

@ -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 <T> Invoker<T> doSelect(List<Invoker<T>> 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<T> 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)]);
}
}

View File

@ -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 <T> Invoker<T> select(List<Invoker<T>> 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);
}
}

View File

@ -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 <T> Invoker<T> doSelect(List<Invoker<T>> 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));
}
}

View File

@ -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<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
protected <T> Invoker<T> doSelect(List<Invoker<T>> 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());
}
}

View File

@ -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=<file-content>
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);
}
}
}

View File

@ -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<String, ScriptEngine> engines = new ConcurrentHashMap<String, ScriptEngine>();
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 <T> List<Invoker<T>> route(List<Invoker<T>> invokers, Invocation invocation) throws RpcException {
try {
List<Invoker<T>> invokersCopy = new ArrayList<Invoker<T>>(invokers);
Compilable compilable = (Compilable) engine;
Bindings bindings = engine.createBindings();
bindings.put("invokers", invokersCopy);
bindings.put("invocation", invocation);
bindings.put("context", RpcContext.getContext());
CompiledScript function = compilable.compile(rule);
Object obj = function.eval(bindings);
if (obj instanceof Invoker[]) {
invokersCopy = Arrays.asList((Invoker<T>[]) obj);
} else if (obj instanceof Object[]) {
invokersCopy = new ArrayList<Invoker<T>>();
for (Object inv : (Object[]) obj) {
invokersCopy.add((Invoker<T>)inv);
}
} else {
invokersCopy = (List<Invoker<T>>) obj;
}
return invokersCopy;
} catch (ScriptException e) {
//fail then ignore rule .invokers.
logger.error("route error , rule has been ignored .rule :"+ rule + ",invocation:" + invocation + ",url :"+(RpcContext.getContext().getInvoker() == null ? "" : RpcContext.getContext().getInvoker().getUrl()), e);
return invokers;
}
}
}

View File

@ -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形如
* <ol>
* <li> script://registyAddress?type=js&rule=xxxx
* <li> script:///path/to/routerfile.js?type=js&rule=xxxx
* <li> script://D:\path\to\routerfile.js?type=js&rule=xxxx
* <li> script://C:/path/to/routerfile.js?type=js&rule=xxxx
* </ol>
* URL的Host一段包含的是Script Router内容的来源RegistryFile 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);
}
}

View File

@ -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<T> implements Invoker<T> {
private static final Logger logger = LoggerFactory
.getLogger(AbstractClusterInvoker.class);
protected final Directory<T> directory;
protected final boolean availablecheck;
private volatile boolean destroyed = false;
private volatile Invoker<T> stickyInvoker = null;
public AbstractClusterInvoker(Directory<T> directory) {
this(directory, directory.getUrl());
}
public AbstractClusterInvoker(Directory<T> directory, URL url) {
if (directory == null)
throw new IllegalArgumentException("service directory == null");
this.directory = directory ;
this.availablecheck = url.getBooleanParameter(RpcConstants.CLUSTER_AVAILABLE_CHECK_KEY, RpcConstants.DEFAULT_CLUSTER_AVAILABLE_CHECK) ;
}
public Class<T> getInterface() {
return directory.getInterface();
}
public URL getUrl() {
return directory.getUrl();
}
public boolean isAvailable() {
Invoker<T> invoker = stickyInvoker;
if (invoker != null) {
return invoker.isAvailable();
}
return directory.isAvailable();
}
public void destroy() {
directory.destroy();
destroyed = true;
}
/**
* 使用loadbalance选择invoker.</br>
* a)先lb选择如果在selected列表中 或者 不可用且做检验时进入下一步(重选),否则直接返回</br>
* b)重选验证规则selected > available .保证重选出的结果尽量不在select中并且是可用的
*
* @param availablecheck 如果设置true在选择的时候先选invoker.available == true
* @param selected 已选过的invoker.注意输入保证不重复
*
*/
protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> 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<T> invoker = doselect(loadbalance, invocation, invokers, selected);
if (sticky){
stickyInvoker = invoker;
}
return invoker;
}
private Invoker<T> doselect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
if (invokers == null || invokers.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<T> invoker = loadbalance.select(invokers, invocation);
//如果 selected中包含优先判断 或者 不可用&&availablecheck=true 则重试.
if( (selected != null && selected.contains(invoker))
||(!invoker.isAvailable() && getUrl()!=null && availablecheck)){
try{
Invoker<T> rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck);
if(rinvoker != null){
invoker = rinvoker;
}else{
//看下第一次选的位置如果不是最后+1位置.
int index = invokers.indexOf(invoker);
try{
//最后在避免碰撞
invoker = index <invokers.size()-1?invokers.get(index+1) :invoker;
}catch (Exception e) {
logger.warn(e.getMessage()+" may because invokers list dynamic change, ignore.",e);
}
}
}catch (Throwable t){
logger.error("clustor relselect fail reason is :"+t.getMessage() +" if can not slove ,you can set cluster.availablecheck=false in url",t);
}
}
return invoker;
}
/**
* 重选先从非selected的列表中选择没有在从selected列表中选择.
* @param loadbalance
* @param invocation
* @param invokers
* @param selected
* @return
* @throws RpcException
*/
private Invoker<T> reselect(LoadBalance loadbalance,Invocation invocation,
List<Invoker<T>> invokers, List<Invoker<T>> selected ,boolean availablecheck)
throws RpcException {
//预先分配一个这个列表是一定会用到的.
List<Invoker<T>> reselectInvokers = new ArrayList<Invoker<T>>(invokers.size()>1?(invokers.size()-1):invokers.size());
//先从非select中选
if( availablecheck ){ //选isAvailable 的非select
for(Invoker<T> 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<T> 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<T> 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<Invoker<T>> 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<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException;
}

View File

@ -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<T> implements Directory<T> {
private final URL url ;
private Boolean destroyed = false;
private List<Router> routers = new ArrayList<Router>();
public AbstractDirectory(URL url) {
this(url, null);
}
public AbstractDirectory(URL url, List<Router> routers) {
if (url == null)
throw new IllegalArgumentException("url == null");
if (routers == null){
routers = new ArrayList<Router>();
}
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<Invoker<T>> list(Invocation invocation) throws RpcException {
List<Invoker<T>> invokers = doList(invocation);
for (Router router: routers){
invokers = router.route(invokers, invocation);
}
return invokers;
}
public URL getUrl() {
return url;
}
public List<Router> getRouters(){
return routers;
}
protected abstract List<Invoker<T>> doList(Invocation invocation) throws RpcException ;
protected void setRouters(List<Router> r){
routers = r;
}
}

View File

@ -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 <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new AbstractClusterInvoker<T>(directory) {
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
return invoker.invoke(invocation);
}
}
throw new RpcException("No provider available in " + invokers);
}
};
}
}

View File

@ -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<T> extends AbstractClusterInvoker<T> {
public AvailableClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
return invoker.invoke(invocation);
}
}
throw new RpcException("No provider available in " + invokers);
}
}

View File

@ -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<String, String> localMap) {
Map<String, String> map = new HashMap<String, String>();
Map<String, String> remoteMap = remoteUrl.getParameters();
if (remoteMap != null && remoteMap.size() > 0) {
map.putAll(remoteMap);
}
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() {}
}

View File

@ -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;
/**
* 失败自动恢复后台记录失败请求定时重发通常用于消息通知操作
*
* <a href="http://en.wikipedia.org/wiki/Failback">Failback</a>
*
* @author william.liangf
*/
@Extension(FailbackCluster.NAME)
public class FailbackCluster implements Cluster {
public final static String NAME = "failback";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailbackClusterInvoker<T>(directory);
}
}

View File

@ -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<T> extends AbstractClusterInvoker<T> {
public FailbackClusterInvoker(Directory<T> 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<Invocation, AbstractClusterInvoker<?>> failed = new ConcurrentHashMap<Invocation, AbstractClusterInvoker<?>>();
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<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>(
failed).entrySet()) {
Invocation invocation = entry.getKey();
Invoker<?> invoker = entry.getValue();
try {
invoker.invoke(invocation);
failed.remove(invocation);
} catch (Throwable e) {
logger.error("Failed retry to invoke " + invocation + ", waiting again.", e);
}
}
}
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
Invoker<T> 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
}
}
}

View File

@ -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;
/**
* 快速失败只发起一次调用失败立即报错通常用于非幂等性的写操作</br>
* <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
*
* @author william.liangf
*/
@Extension(FailfastCluster.NAME)
public class FailfastCluster implements Cluster {
public final static String NAME = "failfast";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailfastClusterInvoker<T>(directory);
}
}

View File

@ -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;
/**
* 快速失败只发起一次调用失败立即报错通常用于非幂等性的写操作</br>
* <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
*
* @author william.liangf
* @author chao.liuc
*
*/
public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T>{
public FailfastClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
Invoker<T> 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);
}
}
}

View File

@ -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;
/**
* 失败转移当出现失败重试其它服务器通常用于读操作但重试会带来更长延迟 <a
* href="http://en.wikipedia.org/wiki/Failover">Failover</a>
*
* @author william.liangf
*/
@Extension(FailoverCluster.NAME)
public class FailoverCluster implements Cluster {
public final static String NAME = "failover";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailoverClusterInvoker<T>(directory);
}
}

View File

@ -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;
/**
* 失败转移当出现失败重试其它服务器通常用于读操作但重试会带来更长延迟
*
* <a href="http://en.wikipedia.org/wiki/Failover">Failover</a>
* @author william.liangf
*
*/
public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T>{
public FailoverClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> 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<Invoker<T>> invoked = new ArrayList<Invoker<T>>(invokers.size()); // invoked invokers.
Set<URL> providers = new HashSet<URL>(len);
for (int i = 0; i < len; i++) {
//boolean pp = false; // is provider problem.
Invoker<T> 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<URL> urls = new ArrayList<URL>(invokers.size());
for(Invoker<T> 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);
}
}

View File

@ -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;
/**
* 失败安全出现异常时直接忽略通常用于写入审计日志等操作 <a
* href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
*
* @author william.liangf
*/
@Extension(FailsafeCluster.NAME)
public class FailsafeCluster implements Cluster {
public final static String NAME = "failsafe";
public <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new FailsafeClusterInvoker<T>(directory);
}
}

View File

@ -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;
/**
* 失败安全出现异常时直接忽略通常用于写入审计日志等操作
*
* <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
*
* @author william.liangf
*/
public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T>{
private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class);
public FailsafeClusterInvoker(Directory<T> directory) {
super(directory);
}
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
Invoker<T> 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
}
}
}

View File

@ -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 <T> Invoker<T> merge(Directory<T> directory) throws RpcException {
return new ForkingClusterInvoker<T>(directory);
}
}

View File

@ -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<T> extends AbstractClusterInvoker<T>{
public ForkingClusterInvoker(Directory<T> directory) {
super(directory);
}
private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("forking-cluster-timer", true));
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
final List<Invoker<T>> 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<Invoker<T>>();
for (int i = 0; i < forks; i++) {
//在invoker列表(排除selected),如果没有选够,则存在重复循环问题.见select实现.
Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);
if(!selected.contains(invoker)){//防止重复添加invoker
selected.add(invoker);
}
}
}
final AtomicInteger count = new AtomicInteger();
final BlockingQueue<Result> ref = new LinkedBlockingQueue<Result>();
for (final Invoker<T> 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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
com.alibaba.dubbo.rpc.cluster.router.FileRouterFactory
com.alibaba.dubbo.rpc.cluster.router.ScriptRouterFactory

View File

@ -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<Invoker<StickyTest>> invokers = new ArrayList<Invoker<StickyTest>>();
Invoker<StickyTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<StickyTest> invoker2 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<StickyTest> dic ;
Result result = new RpcResult();
StickyClusterInvoker<StickyTest> 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<StickyTest>(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<T> extends AbstractClusterInvoker<T>{
private Invoker<T> selectedInvoker ;
public StickyClusterInvoker(Directory<T> directory) {
super(directory);
}
public StickyClusterInvoker(Directory<T> directory,URL url) {
super(directory, url);
}
@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException {
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
selectedInvoker = invoker ;
return null;
}
public Invoker<T> getSelectedInvoker() {
return selectedInvoker;
}
}
}

View File

@ -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;
/**
* <code>TestService</code>
*/
public interface DemoService
{
String sayHello(String name);
int plus(int a,int b);
}

View File

@ -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;
/**
* <code>TestService</code>
*/
public class DemoServiceLocal implements DemoService {
public DemoServiceLocal(DemoService demoService){
}
public String sayHello(String name) {
return name;
}
public int plus(int a, int b) {
return a + b;
}
public void ondisconnect(){
}
public void onconnect(){
}
}

View File

@ -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;
}
}

View File

@ -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;
/**
* <code>TestService</code>
*/
public class DemoServiceStub implements DemoService {
public DemoServiceStub(DemoService demoService){
}
public String sayHello(String name) {
return name;
}
public int plus(int a, int b) {
return a + b;
}
}

View File

@ -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;
}
}

View File

@ -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<Invoker<LoadBalanceTest>> invokers = new ArrayList<Invoker<LoadBalanceTest>>();
Invoker<LoadBalanceTest> invoker1 ;
Invoker<LoadBalanceTest> invoker2 ;
Invoker<LoadBalanceTest> invoker3 ;
Invoker<LoadBalanceTest> invoker4 ;
Invoker<LoadBalanceTest> 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<Invoker,AtomicLong> 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<Invoker,AtomicLong> 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())) <runs/(0f+invokers.size()));
}
}
@Test
public void testLeastActiveLoadBalance_select() {
int runs = 10000;
Map<Invoker,AtomicLong> 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())) <runs/(0f+invokers.size()));
}
}
public Map<Invoker,AtomicLong> getInvokeCounter(int runs,String loadbalanceName) {
Map<Invoker,AtomicLong> counter = new ConcurrentHashMap<Invoker,AtomicLong>();
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName);
for(Invoker invoker :invokers){
counter.put(invoker, new AtomicLong(0));
}
for(int i=0;i<runs;i++){
Invoker sinvoker = lb.select(invokers, invocation);
counter.get(sinvoker).incrementAndGet();
}
return counter;
}
}

View File

@ -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.cluster.router;
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;
public class MockInvoker<T> implements Invoker<T> {
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<T> 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() {
}
}

View File

@ -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<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>());
List<Invoker<String>> 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.size(); i++){ " +
"if (invokers.get(i).isAvailable()) {" +
"result.add(invokers.get(i)) ;" +
"}" +
"} ; " +
"return result;";
String script = "function route(invokers,invocation,context){" + rule + "} route(invokers,invocation,context)";
Router router = new ScriptRouterFactory().getRouter(getRouteUrl(script));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(false) ;
Invoker<String> invoker2 = new MockInvoker<String>(true) ;
Invoker<String> invoker3 = new MockInvoker<String>(true) ;
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
List<Invoker<String>> fileredInvokers = router.route(invokers, new RpcInvocation());
Assert.assertEquals(2, fileredInvokers.size());
Assert.assertEquals(invoker2, fileredInvokers.get(0));
Assert.assertEquals(invoker3, fileredInvokers.get(1));
}
//TODO 异常场景测试
}

View File

@ -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<Invoker<FileRouterEngineTest>> invokers = new ArrayList<Invoker<FileRouterEngineTest>>();
Invoker<FileRouterEngineTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<FileRouterEngineTest> invoker2 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FileRouterEngineTest> 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<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();
Assert.assertEquals(invoker2, invoker);
}
}
@Test
public void testRouteAvailable() {
URL url = initUrl("availablerule.javascript");
initInvocation("method1");
initDic(url);
initInvokers(url);
MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> 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<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();
Assert.assertEquals(invoker1, invoker);
}
}
{
initInvocation("method2");
initDic(url);
initInvokers(url, true, true);
MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(
dic, url);
for (int i = 0; i < 100; i++) {
sinvoker.invoke(invocation);
Invoker<FileRouterEngineTest> 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<FileRouterEngineTest>(url, invokers, Arrays.asList(routerFactory.getRouter(url)));
}
static class MockClusterInvoker<T> extends AbstractClusterInvoker<T> {
private Invoker<T> selectedInvoker;
public MockClusterInvoker(Directory<T> directory) {
super(directory);
}
public MockClusterInvoker(Directory<T> directory, URL url) {
super(directory, url);
}
@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException {
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
selectedInvoker = invoker;
return null;
}
public Invoker<T> getSelectedInvoker() {
return selectedInvoker;
}
}
}

View File

@ -0,0 +1,11 @@
function route(invokers,invocation,context){
var result = new java.util.ArrayList(invokers.size());
for (i=0;i<invokers.size(); i++){
if (invokers.get(i).isAvailable()) {
result.add(invokers.get(i)) ;
}
} ;
return result;
};
route(invokers,invocation,context);

View File

@ -0,0 +1,10 @@
function route(invokers,invocation,context){
var result = new java.util.ArrayList();
if (invokers.size()>1 && invocation.getMethodName() .equals("method1")) {
result.add(invokers.get(0)) ;
} else {
result.add(invokers.get(1)) ;
}
return result;
};
route(invokers,invocation,context);

View File

@ -0,0 +1,11 @@
function route(invokers,invocation,context){
var result = new java.util.ArrayList(invokers.size());
for (i=0;i<invokers.size(); i++){
if (!invokers.get(i).isAvailable()) {
result.add(invokers.get(i)) ;
}
} ;
return result;
};
route(invokers,invocation,context);

View File

@ -0,0 +1,405 @@
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF 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.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.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;
import com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance;
import com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
import com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance;
/**
* AbstractClusterInvokerTest
* @author chao.liuc
*
*/
@SuppressWarnings("rawtypes")
public class AbstractClusterInvokerTest {
List<Invoker<AbstractClusterInvokerTest>> invokers = new ArrayList<Invoker<AbstractClusterInvokerTest>>();
List<Invoker<AbstractClusterInvokerTest>> selectedInvokers = new ArrayList<Invoker<AbstractClusterInvokerTest>>();
AbstractClusterInvoker<AbstractClusterInvokerTest> cluster;
AbstractClusterInvoker<AbstractClusterInvokerTest> cluster_nocheck;
Directory<AbstractClusterInvokerTest> dic ;
Invocation invocation;
URL url = URL.valueOf("registry://localhost:9090");
Invoker<AbstractClusterInvokerTest> invoker1 ;
Invoker<AbstractClusterInvokerTest> invoker2 ;
Invoker<AbstractClusterInvokerTest> invoker3 ;
Invoker<AbstractClusterInvokerTest> invoker4 ;
Invoker<AbstractClusterInvokerTest> 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<runs;i++){
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker2);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker4);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker3);
selectedInvokers.add(invoker5);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
for(int i=0;i<runs;i++){
selectedInvokers.clear();
selectedInvokers.add(invoker1);
selectedInvokers.add(invoker2);
selectedInvokers.add(invoker3);
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
Assert.assertEquals(true,sinvoker.isAvailable());
}
}
/**
* 测试均衡.
*/
@Test
public void testSelectBalance(){
LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);
initlistsize5();
Map<Invoker,AtomicLong> counter = new ConcurrentHashMap<Invoker,AtomicLong>();
for(Invoker invoker :invokers){
counter.put(invoker, new AtomicLong(0));
}
int runs = 1000;
for(int i=0;i<runs;i++){
selectedInvokers.clear();
Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);
counter.get(sinvoker).incrementAndGet();
}
for (Invoker minvoker :counter.keySet() ){
Long count = counter.get(minvoker).get();
// System.out.println(count);
if(minvoker.isAvailable())
Assert.assertTrue("count should > 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");
}
}

View File

@ -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<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();
URL url = URL.valueOf("test://test:11/test");
Invoker<DemoService> invoker = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<DemoService> 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<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
invoker.invoke(invocation);
Assert.assertNull(RpcContext.getContext().getInvoker());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvokerToNoException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
}

View File

@ -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<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test");
Invoker<FailbackClusterInvokerTest> invoker = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FailbackClusterInvokerTest> 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<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
invoker.invoke(invocation);
Assert.assertNull(RpcContext.getContext().getInvoker());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvokerToNoException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
@Test()
public void testRetryFailed() {
resetInvokerToException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic);
invoker.invoke(invocation);
Assert.assertNull(RpcContext.getContext().getInvoker());
invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so
// it can be invoke successfully
}
}

View File

@ -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<Invoker<FailfastClusterInvokerTest>> invokers = new ArrayList<Invoker<FailfastClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test");
Invoker<FailfastClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FailfastClusterInvokerTest> 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<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<FailfastClusterInvokerTest>(dic);
invoker.invoke(invocation);
Assert.assertSame(invoker1, RpcContext.getContext().getInvoker());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvoker1ToNoException();
FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<FailfastClusterInvokerTest>(dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
}

View File

@ -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<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>();
int retries = 5;
URL url = URL.valueOf("test://test:11/test?retries="+retries);
Invoker<FailoverClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<FailoverClusterInvokerTest> invoker2 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<FailoverClusterInvokerTest> 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<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(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<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(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<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(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);
}
}
}

View File

@ -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<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test?forks=2");
Invoker<ForkingClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class);
Invoker<ForkingClusterInvokerTest> invoker2 = EasyMock.createMock(Invoker.class);
Invoker<ForkingClusterInvokerTest> invoker3 = EasyMock.createMock(Invoker.class);
Invocation invocation;
Directory<ForkingClusterInvokerTest> 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<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
Assert.assertNull(invoker.invoke(invocation).getResult());
Assert.assertNotNull(invoker.invoke(invocation).getException());
}
@Test()
public void testInvokeNoExceptoin() {
resetInvokerToNoException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
Result ret = invoker.invoke(invocation);
Assert.assertSame(result, ret);
}
}

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright 1999-2011 Alibaba Group.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="CONSOLE" />
</root>
</log4j:configuration>

47
dubbo-common/pom.xml Normal file
View File

@ -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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-parent</artifactId>
<version>2.0.7</version>
</parent>
<artifactId>dubbo-common</artifactId>
<packaging>jar</packaging>
<name>Dubbo Common Module</name>
<description>The common module of dubbo project</description>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>hessian.lite</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -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名
* <p>
* 如果{@link URL}这些Key都没有Value使用 缺省的扩展在接口的{@link Extension}中设定的值<br>
* 比如<code>String[] {"key1", "key2"}</code>表示
* <ol>
* <li>先在URL上找key1的Value作为要Adapt成的Extension名
* <li>key1没有Value则使用key2的Value作为要Adapt成的Extension名
* <li>key2没有Value使用缺省的扩展
* <li>如果没有设定缺省扩展则方法调用会抛出{@link IllegalStateException}
* </ol>
* <p>
* 如果不设置则缺省使用Extension接口类名的点分隔小写字串<br>
* 即对于Extension接口{@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}的缺省值为<code>String[] {"yyy.invoker.wrapper"}</code>
*
* @see Extension#value()
*/
String[] value() default {};
}

View File

@ -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<String> 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<String> 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(){
}
}

View File

@ -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 {
/**
* 扩展点名称<br>
*
* 如果注解在扩展的接口上则缺省的扩展点<p>
*/
String value() default "";
}

View File

@ -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使用的扩展点获取<p>
* <ul>
* <li>自动注入关联扩展点</li>
* <li>自动Wrap上扩展点的Wrap类</li>
* <li>缺省获得的的扩展点是一个Adaptive Instance
* </ul>
*
* @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">JDK5.0的自动发现机制实现</a>
*
* @author <a href="mailto:liangfei0201@gmail.com">liangfei</a>
* @author ding.lid
*
* @see Extension
* @see Adaptive
* @see Autoproxy
*/
public class ExtensionLoader<T> {
private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
private final Class<?> type;
private final Reference<Map<String, Class<?>>> cachedClasses = new Reference<Map<String,Class<?>>>();
private final ConcurrentMap<String, Reference<Object>> cachedInstances = new ConcurrentHashMap<String, Reference<Object>>();
private volatile Class<?> cachedAdaptiveClass = null;
private final Reference<Object> cachedAdaptiveInstance = new Reference<Object>();
private Set<Class<?>> cachedWrapperClasses;
private String cachedDefaultName;
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
private 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<Object> reference = cachedInstances.get(name);
if (reference == null) {
cachedInstances.putIfAbsent(name, new Reference<Object>());
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<String> getSupportedExtensions() {
Map<String, Class<?>> clazzes = getExtensionClasses();
return Collections.unmodifiableSet(new TreeSet<String>(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<Class<?>> 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<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> 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<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
String fileName = null;
try {
fileName = SERVICES_DIRECTORY + type.getName();
Enumeration<java.net.URL> 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<Class<?>> autoproxies = cachedWrapperClasses;
if (autoproxies == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
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 = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
type.getName(), ExtensionLoader.class.getName(), type.getName());
code.append(s);
// return statement
if (!rt.equals(void.class)) {
code.append("return ");
}
s = String.format("extension.%s(", method.getName());
code.append(s);
for (int i = 0; i < pts.length; i++) {
if (i != 0)
code.append(", ");
code.append("arg").append(i);
}
code.append(");");
}
cg.addMethod(method.getName(), method.getModifiers(), rt, pts,
method.getExceptionTypes(), code.toString());
}
return cg.toClass();
}
private static ClassLoader findClassLoader() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null) {
return classLoader;
}
classLoader = ExtensionLoader.class.getClassLoader();
return classLoader;
}
}

View File

@ -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;
import com.alibaba.dubbo.common.URL;
/**
* Node. (API/SPI, Prototype, ThreadSafe)
*
* @author william.liangf
*/
public interface Node {
/**
* get url.
*
* @return url.
*/
URL getUrl();
/**
* is available.
*
* @return available.
*/
boolean isAvailable();
/**
* destroy.
*/
void destroy();
}

View File

@ -0,0 +1,776 @@
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF 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.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.alibaba.dubbo.common.utils.CollectionUtils;
/**
* URL - Uniform Resource Locator (Immutable, ThreadSafe)
*
* url example:
* <ul>
* <li>http://www.facebook.com/friends?param=value1
* <li>http://username:password@10.20.130.230:8080/list?version=1.0.0
* <li>registry://192.168.1.7:9090/com.alibaba.service1?param1=value1&param2=value2
* <li>ftp://username:password@192.168.1.7:21/1/read.txt
* <li>file:///home/user1/router.js?type=script<br>
* for this case, url protocol = null, url host = null, url path = /home/user1/router.js
* <li>file:///D:/1/router.js?type=script<br>
* for this case, url protocol = null, url host = null, url path = /D:/1/router.js
* </ul>
*
* @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<String, String> 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<String, String>) 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<String, String> parameters) {
this(protocol, null, null, host, port, null, parameters);
}
public URL(String protocol, String host, int port, String path) {
this(protocol, null, null, host, port, path, (Map<String, String>) null);
}
public URL(String protocol, String host, int port, String path, String... pairs) {
this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));
}
public URL(String protocol, String host, int port, String path, Map<String, String> parameters) {
this(protocol, null, null, host, port, path, parameters);
}
public URL(String protocol, String username, String password, String host, int port, String path) {
this(protocol, username, password, host, port, path, (Map<String, String>) null);
}
public URL(String protocol, String username, String password, String host, int port, String path, String... pairs) {
this(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs));
}
public URL(String protocol, String username, String password, String host, int port, String path, Map<String, String> parameters) {
if ((username == null || username.length() == 0)
&& password != null && password.length() > 0) {
throw new IllegalArgumentException("Invalid url, password without username!");
}
this.protocol = protocol;
this.username = username;
this.password = password;
this.host = host;
this.port = (port < 0 ? 0 : port);
this.path = path;
// trim the beginning "/"
while(path != null && path.startsWith("/")) {
path = path.substring(1);
}
this.parameters = Collections.unmodifiableMap(parameters != null ? new HashMap<String, String>(parameters) : new HashMap<String, String>(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<String, String> map = new HashMap<String, String>(getParameters());
map.put(key, value);
return new URL(protocol, username, password, host, port, path, map);
}
public URL addParameterIfAbsent(String key, Object value) {
if (key == null || key.length() == 0
|| value == null || String.valueOf(value).length() == 0) {
return this;
}
if (hasParameter(key)) {
return this;
}
Map<String, String> map = new HashMap<String, String>(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<String, String> parameters) {
if (parameters == null || parameters.size() == 0) {
return this;
}
Map<String, String> map = new HashMap<String, String>(getParameters());
map.putAll(parameters);
return new URL(protocol, username, password, host, port, path, map);
}
public URL addParametersIfAbsent(Map<String, String> parameters) {
if (parameters == null || parameters.size() == 0) {
return this;
}
Map<String, String> map = new HashMap<String, String>(parameters);
map.putAll(getParameters());
return new URL(protocol, username, password, host, port, path, map);
}
public URL addParameters(String... pairs) {
if (pairs == null || pairs.length == 0) {
return this;
}
if (pairs.length % 2 != 0) {
throw new IllegalArgumentException("Map pairs can not be odd number.");
}
Map<String, String> map = new HashMap<String, String>();
int len = pairs.length / 2;
for (int i = 0; i < len; i ++) {
map.put(pairs[2 * i], pairs[2 * i + 1]);
}
return addParameters(map);
}
public URL removeParameter(String key) {
if (key == null || key.length() == 0) {
return this;
}
return removeParameters(key);
}
public URL removeParameters(Collection<String> 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<String, String> map = new HashMap<String, String>(getParameters());
for (String key : keys) {
map.remove(key);
}
if (map.size() == getParameters().size()) {
return this;
}
return new URL(protocol, username, password, host, port, path, map);
}
public URL cleatParameters() {
return new URL(protocol, username, password, host, port, path, new HashMap<String, String>());
}
/**
* 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<String, String> parameters = null;
int i = url.indexOf("?"); // seperator between body and parameters
if (i >= 0) {
String[] parts = url.substring(i + 1).split("\\&");
parameters = new HashMap<String, String>();
for (String part : parts) {
part = part.trim();
if (part.length() > 0) {
int j = part.indexOf('=');
if (j >= 0) {
parameters.put(part.substring(0, j), part.substring(j + 1));
} else {
parameters.put(part, part);
}
}
}
url = url.substring(0, i);
}
i = url.indexOf("://");
if (i >= 0) {
if(i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\"");
protocol = url.substring(0, i);
url = url.substring(i + 3);
}
else {
// case: file:/path/to/file.txt
i = url.indexOf(":/");
if(i>=0) {
if(i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\"");
protocol = url.substring(0, i);
url = url.substring(i + 1);
}
}
i = url.indexOf("/");
if (i >= 0) {
path = url.substring(i + 1);
url = url.substring(0, i);
}
i = url.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<String, String> 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<String, String> entry : new TreeMap<String, String>(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<String, String> 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;
}
}

View File

@ -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<URL> urls = Thread.currentThread().getContextClassLoader().getResources(path);
Set<String> files = new HashSet<String>();
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);
}
}
}

View File

@ -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 = "<init>";
private static final Map<ClassLoader, ClassPool> POOL_MAP = new ConcurrentHashMap<ClassLoader, ClassPool>(); //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<String> mInterfaces;
private List<String> mFields, mConstructors, mMethods;
private Map<String, Method> mCopyMethods; // <method desc,method instance>
private Map<String, Constructor<?>> mCopyConstructors; // <constructor desc,constructor instance>
private boolean mDefaultConstructor = false;
private ClassGenerator(){}
private ClassGenerator(ClassPool pool)
{
mPool = pool;
}
public String getClassName()
{
return mClassName;
}
public ClassGenerator setClassName(String name)
{
mClassName = name;
return this;
}
public ClassGenerator addInterface(String cn)
{
if( mInterfaces == null )
mInterfaces = new HashSet<String>();
mInterfaces.add(cn);
return this;
}
public ClassGenerator addInterface(Class<?> cl)
{
return addInterface(cl.getName());
}
public ClassGenerator setSuperClass(String cn)
{
mSuperClass = cn;
return this;
}
public ClassGenerator setSuperClass(Class<?> cl)
{
mSuperClass = cl.getName();
return this;
}
public ClassGenerator addField(String code)
{
if( mFields == null )
mFields = new ArrayList<String>();
mFields.add(code);
return this;
}
public ClassGenerator addField(String name, int mod, Class<?> type)
{
return addField(name, mod, type, null);
}
public ClassGenerator addField(String name, int mod, Class<?> type, String def)
{
StringBuilder sb = new StringBuilder();
sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(type)).append(' ');
sb.append(name);
if( def != null && def.length() > 0 )
{
sb.append('=');
sb.append(def);
}
sb.append(';');
return addField(sb.toString());
}
public ClassGenerator addMethod(String code)
{
if( mMethods == null )
mMethods = new ArrayList<String>();
mMethods.add(code);
return this;
}
public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, String body)
{
return addMethod(name, mod, rt, pts, null, body);
}
public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, Class<?>[] ets, String body)
{
StringBuilder sb = new StringBuilder();
sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(rt)).append(' ').append(name);
sb.append('(');
for(int i=0;i<pts.length;i++)
{
if( i > 0 )
sb.append(',');
sb.append(ReflectUtils.getName(pts[i]));
sb.append(" arg").append(i);
}
sb.append(')');
if( ets != null && ets.length > 0 )
{
sb.append(" throws ");
for(int i=0;i<ets.length;i++)
{
if( i > 0 )
sb.append(',');
sb.append(ReflectUtils.getName(ets[i]));
}
}
sb.append('{').append(body).append('}');
return addMethod(sb.toString());
}
public ClassGenerator addMethod(Method m)
{
addMethod(m.getName(), m);
return this;
}
public ClassGenerator addMethod(String name, Method m)
{
String desc = name + ReflectUtils.getDescWithoutMethodName(m);
addMethod(':' + desc);
if( mCopyMethods == null )
mCopyMethods = new ConcurrentHashMap<String, Method>(8);
mCopyMethods.put(desc, m);
return this;
}
public ClassGenerator addConstructor(String code)
{
if( mConstructors == null )
mConstructors = new LinkedList<String>();
mConstructors.add(code);
return this;
}
public ClassGenerator addConstructor(int mod, Class<?>[] pts, String body)
{
return addConstructor(mod, pts, null, body);
}
public ClassGenerator addConstructor(int mod, Class<?>[] pts, Class<?>[] ets, String body)
{
StringBuilder sb = new StringBuilder();
sb.append(modifier(mod)).append(' ').append(SIMPLE_NAME_TAG);
sb.append('(');
for(int i=0;i<pts.length;i++)
{
if( i > 0 )
sb.append(',');
sb.append(ReflectUtils.getName(pts[i]));
sb.append(" arg").append(i);
}
sb.append(')');
if( ets != null && ets.length > 0 )
{
sb.append(" throws ");
for(int i=0;i<ets.length;i++)
{
if( i > 0 )
sb.append(',');
sb.append(ReflectUtils.getName(ets[i]));
}
}
sb.append('{').append(body).append('}');
return addConstructor(sb.toString());
}
public ClassGenerator addConstructor(Constructor<?> c)
{
String desc = ReflectUtils.getDesc(c);
addConstructor(":"+desc);
if( mCopyConstructors == null )
mCopyConstructors = new ConcurrentHashMap<String, Constructor<?>>(4);
mCopyConstructors.put(desc, c);
return this;
}
public ClassGenerator addDefaultConstructor()
{
mDefaultConstructor = true;
return this;
}
public 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 "";
}
}

View File

@ -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<dcs.length;i++)
{
if( !Modifier.isPublic(dcs[i].getModifiers()) )
{
String npkg = dcs[i].getPackage().getName();
if( pkg == null )
{
pkg = npkg;
}
else
{
if( !pkg.equals(npkg) )
throw new IllegalArgumentException("non-public interfaces class from different packages");
}
}
ccp.addField("private " + dcs[i].getName() + " d" + i + ";");
code.append("d").append(i).append(" = (").append(dcs[i].getName()).append(")$1[").append(i).append("];\n");
if( MixinAware.class.isAssignableFrom(dcs[i]) )
code.append("d").append(i).append(".setMixinInstance(this);\n");
}
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{ Object[].class }, code.toString());
// impl methods.
Set<String> worked = new HashSet<String>();
for(int i=0;i<ics.length;i++)
{
if( !Modifier.isPublic(ics[i].getModifiers()) )
{
String npkg = ics[i].getPackage().getName();
if( pkg == null )
{
pkg = npkg;
}
else
{
if( !pkg.equals(npkg) )
throw new IllegalArgumentException("non-public delegate class from different packages");
}
}
ccp.addInterface(ics[i]);
for( Method method : ics[i].getMethods() )
{
if( "java.lang.Object".equals(method.getDeclaringClass().getName()) )
continue;
String desc = ReflectUtils.getDesc(method);
if( worked.contains(desc) )
continue;
worked.add(desc);
int ix = findMethod(dcs, desc);
if( ix < 0 )
throw new RuntimeException("Missing method [" + desc + "] implement.");
Class<?> rt = method.getReturnType();
String mn = method.getName();
if( Void.TYPE.equals(rt) )
ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
"d" + ix + "." + mn + "($$);");
else
ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
"return ($r)d" + ix + "." + mn + "($$);");
}
}
if( pkg == null )
pkg = PACKAGE_NAME;
// create MixinInstance class.
String micn = pkg + ".mixin" + id;
ccp.setClassName(micn);
ccp.toClass();
// create Mixin class.
String fcn = Mixin.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Mixin.class.getName());
ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }");
Class<?> mixin = ccm.toClass();
return (Mixin)mixin.newInstance();
}
catch(RuntimeException e)
{
throw e;
}
catch(Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
finally
{
// release ClassGenerator
if( ccp != null )
ccp.release();
if( ccm != null )
ccm.release();
}
}
/**
* 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<dcs.length;i++)
{
cl = dcs[i];
methods = cl.getMethods();
for( Method method : methods )
{
if( desc.equals(ReflectUtils.getDesc(method)) )
return i;
}
}
return -1;
}
private static void assertInterfaceArray(Class<?>[] ics)
{
for(int i=0;i<ics.length;i++)
if( !ics[i].isInterface() )
throw new RuntimeException("Class " + ics[i].getName() + " is not a interface.");
}
}

View File

@ -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.common.bytecode;
/**
* NoSuchMethodException.
*
* @author qian.lei
*/
public class NoSuchMethodException extends RuntimeException
{
private static final long serialVersionUID = -2725364246023268766L;
public NoSuchMethodException()
{
super();
}
public NoSuchMethodException(String msg)
{
super(msg);
}
}

View File

@ -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.common.bytecode;
/**
* NoSuchPropertyException.
*
* @author qian.lei
*/
public class NoSuchPropertyException extends RuntimeException
{
private static final long serialVersionUID = -2725364246023268766L;
public NoSuchPropertyException()
{
super();
}
public NoSuchPropertyException(String msg)
{
super(msg);
}
}

View File

@ -0,0 +1,286 @@
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF 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.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.dubbo.common.utils.ClassHelper;
import com.alibaba.dubbo.common.utils.ReflectUtils;
/**
* Proxy.
*
* @author qian.lei
*/
public abstract class Proxy
{
private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ return null; }
};
public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented."); }
};
private static final Map<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();
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<ics.length;i++)
{
String itf = ics[i].getName();
if( !ics[i].isInterface() )
throw new RuntimeException(itf + " is not a interface.");
Class<?> tmp = null;
try
{
tmp = Class.forName(itf, false, cl);
}
catch(ClassNotFoundException e)
{}
if( tmp != ics[i] )
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
sb.append(itf).append(';');
}
// use interface class name list as key.
String key = sb.toString();
// get cache by class loader.
Map<String, Object> cache;
synchronized( ProxyCacheMap )
{
cache = ProxyCacheMap.get(cl);
if( cache == null )
{
cache = new HashMap<String, Object>();
ProxyCacheMap.put(cl, cache);
}
}
Proxy proxy = null;
synchronized( cache )
{
do
{
Object value = cache.get(key);
if( value instanceof Reference<?> )
{
proxy = (Proxy)((Reference<?>)value).get();
if( proxy != null )
return proxy;
}
if( value == PendingGenerationMarker )
{
try{ cache.wait(); }catch(InterruptedException e){}
}
else
{
cache.put(key, PendingGenerationMarker);
break;
}
}
while( true );
}
long id = PROXY_CLASS_COUNTER.getAndIncrement();
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try
{
ccp = ClassGenerator.newInstance(cl);
Set<String> worked = new HashSet<String>();
List<Method> methods = new ArrayList<Method>();
for(int i=0;i<ics.length;i++)
{
if( !Modifier.isPublic(ics[i].getModifiers()) )
{
String npkg = ics[i].getPackage().getName();
if( pkg == null )
{
pkg = npkg;
}
else
{
if( !pkg.equals(npkg) )
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
ccp.addInterface(ics[i]);
for( Method method : ics[i].getMethods() )
{
String desc = ReflectUtils.getDesc(method);
if( worked.contains(desc) )
continue;
worked.add(desc);
int ix = methods.size();
Class<?> rt = method.getReturnType();
Class<?>[] pts = method.getParameterTypes();
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for(int j=0;j<pts.length;j++)
code.append(" args[").append(j).append("] = ($w)$").append(j+1).append(";");
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
if( !Void.TYPE.equals(rt) )
code.append(" return ").append(asArgument(rt, "ret")).append(";");
methods.add(method);
ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
}
}
if( pkg == null )
pkg = PACKAGE_NAME;
// create ProxyInstance class.
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{ InvocationHandler.class }, new Class<?>[0], "handler=$1;");
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// create Proxy class.
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class<?> pc = ccm.toClass();
proxy = (Proxy)pc.newInstance();
}
catch(RuntimeException e)
{
throw e;
}
catch(Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
finally
{
// release ClassGenerator
if( ccp != null )
ccp.release();
if( ccm != null )
ccm.release();
synchronized( cache )
{
if( proxy == null )
cache.remove(key);
else
cache.put(key, new WeakReference<Proxy>(proxy));
cache.notifyAll();
}
}
return proxy;
}
/**
* 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;
}
}

View File

@ -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<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
private static final Wrapper OBJECT_WRAPPER = new Wrapper(){
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<ret.length;i++)
ret[i] = getPropertyValue(instance, pns[i]);
return ret;
}
/**
* set property value.
*
* @param instance instance.
* @param pn property name array.
* @param pv property value array.
*/
public void setPropertyValues(Object instance, String[] pns, Object[] pvs) throws NoSuchPropertyException, IllegalArgumentException
{
if( pns.length != pvs.length )
throw new IllegalArgumentException("pns.length != pvs.length");
for(int i=0;i<pns.length;i++)
setPropertyValue(instance, pns[i], pvs[i]);
}
/**
* get method name array.
*
* @return method name array.
*/
abstract public String[] getMethodNames();
/**
* get method name array.
*
* @return method name array.
*/
abstract public String[] getDeclaredMethodNames();
/**
* has method.
*
* @param name method name.
* @return has or has not.
*/
public boolean hasMethod(String name)
{
for( String mn : getMethodNames() )
if( mn.equals(name) ) return true;
return false;
}
/**
* invoke method.
*
* @param instance instance.
* @param mn method name.
* @param types
* @param args argument array.
* @return return value.
*/
abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
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<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
List<String> mns = new ArrayList<String>(); // method names.
List<String> dmns = new ArrayList<String>(); // declaring method names.
// get all public field.
for( Field f : c.getFields() )
{
String fn = f.getName();
Class<?> ft = f.getType();
if( Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()) )
continue;
c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
pts.put(fn, ft);
}
Method[] methods = c.getMethods();
// get all public method.
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<String,Method> entry : ms.entrySet() )
{
String md = entry.getKey();
Method method = (Method)entry.getValue();
if( ( matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() )
{
String pn = propertyName(matcher.group(1));
c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
pts.put(pn, method.getReturnType());
}
else if( ( matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md) ).matches() )
{
String pn = propertyName(matcher.group(1));
c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
pts.put(pn, method.getReturnType());
}
else if( ( matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() )
{
Class<?> pt = method.getParameterTypes()[0];
String pn = propertyName(matcher.group(1));
c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt,"$3")).append("); return; }");
pts.put(pn, pt);
}
}
c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
ClassGenerator cc = ClassGenerator.newInstance(cl);
cc.setClassName( ( Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw" ) + id );
cc.setSuperClass(Wrapper.class);
cc.addDefaultConstructor();
cc.addField("public static String[] pns;"); // property name array.
cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
cc.addField("public static String[] mns;"); // all method name array.
cc.addField("public static String[] dmns;"); // declared method name array.
for(int i=0,len=ms.size();i<len;i++)
cc.addField("public static Class[] mts" + i + ";");
cc.addMethod("public String[] getPropertyNames(){ return pns; }");
cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
cc.addMethod("public String[] getMethodNames(){ return mns; }");
cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
cc.addMethod(c1.toString());
cc.addMethod(c2.toString());
cc.addMethod(c3.toString());
try
{
Class<?> wc = cc.toClass();
// setup static field.
wc.getField("pts").set(null, pts);
wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
wc.getField("mns").set(null, mns.toArray(new String[0]));
wc.getField("dmns").set(null, dmns.toArray(new String[0]));
int ix = 0;
for( Method m : ms.values() )
wc.getField("mts" + ix++).set(null, m.getParameterTypes());
return (Wrapper)wc.newInstance();
}
catch(RuntimeException e)
{
throw e;
}
catch(Throwable e)
{
throw new RuntimeException(e.getMessage(), e);
}
finally
{
cc.release();
ms.clear();
mns.clear();
dmns.clear();
}
}
private static String arg(Class<?> cl, String name)
{
if( cl.isPrimitive() )
{
if( cl == Boolean.TYPE )
return "((Boolean)" + name + ").booleanValue()";
if( cl == Byte.TYPE )
return "((Byte)" + name + ").byteValue()";
if( cl == Character.TYPE )
return "((Character)" + name + ").charValue()";
if( cl == Double.TYPE )
return "((Number)" + name + ").doubleValue()";
if( cl == Float.TYPE )
return "((Number)" + name + ").floatValue()";
if( cl == Integer.TYPE )
return "((Number)" + name + ").intValue()";
if( cl == Long.TYPE )
return "((Number)" + name + ").longValue()";
if( cl == Short.TYPE )
return "((Number)" + name + ").shortValue()";
throw new RuntimeException("Unknown primitive type: " + cl.getName());
}
return "(" + ReflectUtils.getName(cl) + ")" + name;
}
private static String args(Class<?>[] cs,String name)
{
int len = cs.length;
if( len == 0 ) return "";
StringBuilder sb = new StringBuilder();
for(int i=0;i<len;i++)
{
if( i > 0 )
sb.append(',');
sb.append(arg(cs[i],name+"["+i+"]"));
}
return sb.toString();
}
private static String propertyName(String pn)
{
return pn.length() == 1 || Character.isLowerCase(pn.charAt(1)) ? Character.toLowerCase(pn.charAt(0)) + pn.substring(1) : pn;
}
}

View File

@ -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<Integer, byte[]> DECODE_TABLE_MAP = new ConcurrentHashMap<Integer, byte[]>();
private static ThreadLocal<MessageDigest> MD = new ThreadLocal<MessageDigest>();
/**
* 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<len;i++)
{
b = bs[r++];
cs[w++] = BASE16[ b >> 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<num;i++)
b[w++] = (byte)( hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)) );
return b;
}
/**
* to base64 string.
*
* @param b byte array.
* @return base64 string.
*/
public static String bytes2base64(byte[] b)
{
return bytes2base64(b, 0, b.length, BASE64);
}
/**
* to base64 string.
*
* @param b byte array.
* @return base64 string.
*/
public static String bytes2base64(byte[] b, int offset, int length)
{
return bytes2base64(b, offset, length, BASE64);
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code string(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, String code)
{
return bytes2base64(b, 0, b.length, code);
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code string(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, int offset, int length, String code)
{
if( code.length() < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
return bytes2base64(b, offset, length, code.toCharArray());
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, char[] code)
{
return bytes2base64(b, 0, b.length, code);
}
/**
* to base64 string.
*
* @param bs byte array.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(final byte[] bs, final int off, final int len, final char[] code)
{
if( off < 0 )
throw new IndexOutOfBoundsException("bytes2base64: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("bytes2base64: length < 0, length is " + len );
if( off + len > 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<num;i++)
{
int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8, b3 = bs[r++] & MASK8;
cs[w++] = code[ b1 >> 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<num;i++)
{
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];
int c3 = t[str.charAt(r++)], c4 = t[str.charAt(r++)];
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 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<num;i++)
{
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));
int c3 = indexOf(code, str.charAt(r++)), c4 = indexOf(code, str.charAt(r++));
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 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<len;i++)
if( cs[i] == c ) return i;
return -1;
}
private static byte[] decodeTable(String code)
{
int hash = code.hashCode();
byte[] ret = DECODE_TABLE_MAP.get(hash);
if( ret == null )
{
if( code.length() < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
// create new decode table.
ret = new byte[128];
for(int i=0;i<128;i++) // init table.
ret[i] = -1;
for(int i=0;i<64;i++)
ret[code.charAt(i)] = (byte)i;
DECODE_TABLE_MAP.put(hash, ret);
}
return ret;
}
private static byte[] getMD5(InputStream is, int bs) throws IOException
{
MessageDigest md = getMessageDigest();
byte[] buf = new byte[bs];
while( is.available() > 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(){}
}

View File

@ -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);
}

View File

@ -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 <code>readlimit</code> 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);
}
}

View File

@ -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;
}
}

View File

@ -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
{}
}

View File

@ -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");
}
}

View File

@ -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();
}
}

View File

@ -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<Class<?>, Encoder> GlobalEncoderMap = new HashMap<Class<?>, Encoder>();
private static final Map<Class<?>, Decoder> GlobalDecoderMap = new HashMap<Class<?>, 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<len;i++)
writeValue(Array.get(obj, i), jb, writeClass);
jb.arrayEnd();
}
else if( Map.class.isAssignableFrom(c) )
{
Object key, value;
jb.objectBegin();
for( Map.Entry<Object, Object> entry : ((Map<Object, Object>)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<Object>)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<Enum>)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);
}
}

View File

@ -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<Object> mStack = new Stack<Object>();
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<String, Object>();
} else {
mValue = new HashMap<String, Object>();
}
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<String, Object>)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<Object> items;
if( mType == Object.class || Collection.class.isAssignableFrom(mType)) {
if (! mType.isInterface() && mType != Object.class) {
try {
items = (Collection<Object>) mType.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
} else if (mType.isAssignableFrom(ArrayList.class)) { // List
items = new ArrayList<Object>(count);
} else if (mType.isAssignableFrom(HashSet.class)) { // Set
items = new HashSet<Object>(count);
} else if (mType.isAssignableFrom(LinkedList.class)) { // Queue
items = new LinkedList<Object>();
} else { // Other
items = new ArrayList<Object>(count);
}
} else {
throw new ParseException("Convert error, can not load json array data into class [" + mType.getName() + "].");
}
for(int i=0;i<count;i++)
items.add(mStack.remove(i-count));
ret = items;
}
mStack.pop();
return ret;
}
public void arrayItem(int index) throws ParseException
{
if( mTypes != null && mStack.size() == index+1 )
{
if( index < mTypes.length )
mType = mTypes[index];
else
throw new ParseException("Can not load json array data into [" + name(mTypes) + "].");
}
}
public void arrayItemValue(int index, Object obj, boolean isValue) throws ParseException
{
if( isValue && obj != null )
{
try
{
obj = mConverter.readValue(mType, obj);
}
catch(IOException e)
{
throw new ParseException(e.getMessage());
}
}
mStack.push(obj);
}
private static Object toArray(Class<?> c, Stack<Object> 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<types.length;i++)
{
if( i > 0 )
sb.append(", ");
sb.append(types[i].getName());
}
return sb.toString();
}
}

View File

@ -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> T parse(String json, Class<T> 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> T parse(Reader reader, Class<T> 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<Entry> stack = new Stack<Entry>();
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<int[]> states = new Stack<int[]>();
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);
}
}

View File

@ -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<Object> mArray = new ArrayList<Object>();
/**
* 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();
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<String,Object> mMap = new HashMap<String,Object>();
/**
* 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<String> 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<len;i++)
mMap.put(names[i], values[i]);
}
/**
* put all.
*
* @param map map.
*/
public void putAll(Map<String, Object> map)
{
for( Map.Entry<String, Object> 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<String,Object> 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();
}
}

View File

@ -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<Yylex> LOCAL_LEXER = new ThreadLocal<Yylex>(){};
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;
}
}

View File

@ -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";
}
}
}

View File

@ -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;
}

View File

@ -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<State> mStack = new Stack<State>();
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;i<len;i++)
{
c = str.charAt(i);
if( c < ' ' ) // control char.
{
if( sb == null )
{
sb = new StringBuilder(len<<1);
sb.append(str,0,i);
}
sb.append(CONTROL_CHAR_MAP[c]);
}
else
{
switch( c )
{
case '\\': case '/': case '"':
if( sb == null )
{
sb = new StringBuilder(len<<1);
sb.append(str,0,i);
}
sb.append('\\').append(c);
break;
default:
if( sb != null )
sb.append(c);
}
}
}
return sb == null ? str : sb.toString();
}
}

View File

@ -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.common.json;
/**
* ParseException.
*
* @author qian.lei
*/
public class ParseException extends Exception
{
private static final long serialVersionUID = 8611884051738966316L;
public ParseException()
{
super();
}
public ParseException(String message)
{
super(message);
}
}

View File

@ -0,0 +1,800 @@
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF 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;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 7/3/10 3:12 AM from the specification file
* <tt>/Users/qianlei/dev/proj/dubbo-1.1/dubbo.common/src/main/java/com/alibaba/dubbo/common/json/json.flex</tt>
*/
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 <code>aState</code>
*/
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 <code>false</code>, 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
* <b>cannot</b> be reused (internal buffer is discarded and lost).
* Lexical state is set to <tt>ZZ_INITIAL</tt>.
*
* @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 <tt>pos</tt> 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);
}
}
}
}
}

View File

@ -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 = .
%%
<STR1>{
\" { yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); }
{ESC1}+ { sb.append(yytext()); }
\\\" { sb.append('"'); }
}
<STR2>{
\' { yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); }
{ESC2}+ { sb.append(yytext()); }
\\\' { sb.append('\''); }
}
<STR1,STR2>{
\\\\ { 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()); } }
}
<YYINITIAL>{
\" { 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() +"]"); }
}

View File

@ -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
}

View File

@ -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;
/**
* 日志接口 <p/> 声明引用自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();
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}

View File

@ -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<Appender> 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) {
}
}

View File

@ -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;
}

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