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:
parent
d22223d3bc
commit
10052d4687
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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)]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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内容的来源,Registry、File etc
|
||||
*
|
||||
* @author william.liangf
|
||||
*/
|
||||
@Extension(ScriptRouterFactory.NAME)
|
||||
public class ScriptRouterFactory implements RouterFactory {
|
||||
|
||||
public static final String NAME = "script";
|
||||
|
||||
public Router getRouter(URL url) {
|
||||
return new ScriptRouter(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
com.alibaba.dubbo.rpc.cluster.router.FileRouterFactory
|
||||
com.alibaba.dubbo.rpc.cluster.router.ScriptRouterFactory
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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(){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
@ -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 异常场景测试。
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 {};
|
||||
|
||||
}
|
||||
|
|
@ -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(){
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 "";
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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¶m2=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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 "";
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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(){}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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() +"]"); }
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue