hprose.client.HproseClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hprose-java Show documentation
Show all versions of hprose-java Show documentation
Hprose is a High Performance Remote Object Service Engine.
It is a modern, lightweight, cross-language, cross-platform, object-oriented, high performance, remote dynamic communication middleware. It is not only easy to use, but powerful. You just need a little time to learn, then you can use it to easily construct cross language cross platform distributed application system.
Hprose supports many programming languages, for example:
* AAuto Quicker
* ActionScript
* ASP
* C++
* Dart
* Delphi/Free Pascal
* dotNET(C#, Visual Basic...)
* Golang
* Java
* JavaScript
* Node.js
* Objective-C
* Perl
* PHP
* Python
* Ruby
* ...
Through Hprose, You can conveniently and efficiently intercommunicate between those programming languages.
This project is the implementation of Hprose for Java.
/**********************************************************\
| |
| hprose |
| |
| Official WebSite: http://www.hprose.com/ |
| http://www.hprose.org/ |
| |
\**********************************************************/
/**********************************************************\
* *
* HproseClient.java *
* *
* hprose client class for Java. *
* *
* LastModified: Nov 14, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
package hprose.client;
import hprose.common.HandlerManager;
import hprose.common.HproseCallback;
import hprose.common.HproseCallback1;
import hprose.common.HproseContext;
import hprose.common.HproseErrorEvent;
import hprose.common.HproseException;
import hprose.common.HproseFilter;
import hprose.common.HproseResultMode;
import hprose.common.InvokeSettings;
import hprose.io.ByteBufferStream;
import hprose.io.HproseMode;
import static hprose.io.HproseTags.TagArgument;
import static hprose.io.HproseTags.TagCall;
import static hprose.io.HproseTags.TagEnd;
import static hprose.io.HproseTags.TagError;
import static hprose.io.HproseTags.TagResult;
import hprose.io.serialize.Writer;
import hprose.io.unserialize.Reader;
import hprose.util.ClassUtil;
import hprose.util.StrUtil;
import hprose.util.concurrent.Action;
import hprose.util.concurrent.AsyncCall;
import hprose.util.concurrent.AsyncFunc;
import hprose.util.concurrent.Func;
import hprose.util.concurrent.Promise;
import hprose.util.concurrent.Threads;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class HproseClient extends HandlerManager {
private final static Object[] nullArgs = new Object[0];
private final ArrayList filters = new ArrayList();
private final ArrayList uriList = new ArrayList();
private final AtomicInteger index = new AtomicInteger(-1);
private volatile HproseMode mode;
private volatile int timeout = 30000;
private volatile int retry = 10;
private volatile boolean idempotent = false;
private volatile boolean failswitch = false;
private volatile int failround = 0;
private volatile boolean byref = false;
private volatile boolean simple = false;
protected String uri;
public HproseErrorEvent onError = null;
public Action onFailswitch = null;
protected HproseClient() {
this((String[])null, HproseMode.MemberMode);
}
protected HproseClient(HproseMode mode) {
this((String[])null, mode);
}
protected HproseClient(String uri) {
this(uri, HproseMode.MemberMode);
}
protected HproseClient(String uri, HproseMode mode) {
this(uri == null ? (String[])null : new String[] {uri}, mode);
}
protected HproseClient(String[] uriList) {
this(uriList, HproseMode.MemberMode);
}
protected HproseClient(String[] uriList, HproseMode mode) {
this.mode = mode;
if (uriList != null) {
setUriList(uriList);
}
Threads.registerShutdownHandler(new Runnable() {
public void run() {
close();
}
});
}
public void close() {}
private final static HashMap> clientFactories = new HashMap>();
public static void registerClientFactory(String scheme, Class extends HproseClient> clientClass) {
synchronized (clientFactories) {
clientFactories.put(scheme, clientClass);
}
}
static {
registerClientFactory("tcp", HproseTcpClient.class);
registerClientFactory("tcp4", HproseTcpClient.class);
registerClientFactory("tcp6", HproseTcpClient.class);
registerClientFactory("http", HproseHttpClient.class);
registerClientFactory("https", HproseHttpClient.class);
}
public static HproseClient create(String uri) throws IOException, URISyntaxException {
return create(new String[] { uri }, HproseMode.MemberMode);
}
public static HproseClient create(String uri, HproseMode mode) throws IOException, URISyntaxException {
return create(new String[] { uri }, mode);
}
public static HproseClient create(String[] uriList, HproseMode mode) throws IOException, URISyntaxException {
String scheme = (new URI(uriList[0])).getScheme().toLowerCase();
for (int i = 1, n = uriList.length; i < n; ++i) {
if (!(new URI(uriList[i])).getScheme().toLowerCase().equalsIgnoreCase(scheme)) {
throw new HproseException("Not support multiple protocol.");
}
}
Class extends HproseClient> clientClass = clientFactories.get(scheme);
if (clientClass != null) {
try {
HproseClient client = clientClass.newInstance();
client.mode = mode;
client.useService(uriList);
return client;
}
catch (Exception ex) {
throw new HproseException("This client doesn't support " + scheme + " scheme.");
}
}
throw new HproseException("This client doesn't support " + scheme + " scheme.");
}
public final List getUriList() {
return uriList;
}
private void initUriList() {
Collections.shuffle(this.uriList);
this.index.set(0);
this.failround = 0;
this.uri = this.uriList.get(0);
}
public final void setUriList(List uriList) {
this.uriList.clear();
int n = uriList.size();
for (int i = 0; i < n; i++) {
this.uriList.add(uriList.get(i));
}
this.initUriList();
}
public final void setUriList(String[] uriList) {
this.uriList.clear();
int n = uriList.length;
for (int i = 0; i < n; i++) {
this.uriList.add(uriList[i]);
}
this.initUriList();
}
public final int getTimeout() {
return timeout;
}
public final void setTimeout(int timeout) {
if (timeout < 1) throw new IllegalArgumentException("timeout must be great than 0");
this.timeout = timeout;
}
public final int getRetry() {
return retry;
}
public final void setRetry(int retry) {
this.retry = retry;
}
public final boolean isIdempotent() {
return idempotent;
}
public final void setIdempotent(boolean idempotent) {
this.idempotent = idempotent;
}
public final boolean isFailswitch() {
return failswitch;
}
public final void setFailswitch(boolean failswitch) {
this.failswitch = failswitch;
}
public final int getFailround() {
return failround;
}
public final boolean isByref() {
return byref;
}
public final void setByref(boolean byref) {
this.byref = byref;
}
public final boolean isSimple() {
return simple;
}
public final void setSimple(boolean simple) {
this.simple = simple;
}
public final HproseFilter getFilter() {
if (filters.isEmpty()) {
return null;
}
return filters.get(0);
}
public final void setFilter(HproseFilter filter) {
if (!filters.isEmpty()) {
filters.clear();
}
if (filter != null) {
filters.add(filter);
}
}
public final void addFilter(HproseFilter filter) {
if (filter != null) {
filters.add(filter);
}
}
public final boolean removeFilter(HproseFilter filter) {
return filters.remove(filter);
}
public final void useService(String uri) {
setUriList(new String[] { uri });
}
public final void useService(String[] uriList) {
setUriList(uriList);
}
public final T useService(Class type) {
return useService(type, null);
}
public final T useService(String uri, Class type) {
return useService(uri, type, null);
}
public final T useService(String[] uriList, Class type) {
return useService(uriList, type, null);
}
@SuppressWarnings("unchecked")
public final T useService(Class type, String ns) {
HproseInvocationHandler handler = new HproseInvocationHandler(this, ns);
if (type.isInterface()) {
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class>[]{type}, handler);
}
else {
return (T) Proxy.newProxyInstance(type.getClassLoader(), type.getInterfaces(), handler);
}
}
public final T useService(String uri, Class type, String ns) {
useService(uri);
return useService(type, ns);
}
public final T useService(String[] uriList, Class type, String ns) {
setUriList(uriList);
return useService(type, ns);
}
private ByteBuffer outputFilter(ByteBuffer request, ClientContext context) {
if (request.position() != 0) {
request.flip();
}
for (int i = 0, n = filters.size(); i < n; ++i) {
request = filters.get(i).outputFilter(request, context);
if (request.position() != 0) {
request.flip();
}
}
return request;
}
private ByteBuffer inputFilter(ByteBuffer response, ClientContext context) {
if (response.position() != 0) {
response.flip();
}
for (int i = filters.size() - 1; i >= 0; --i) {
response = filters.get(i).inputFilter(response, context);
if (response.position() != 0) {
response.flip();
}
}
return response;
}
private Promise beforeFilterHandler(ByteBuffer request, final ClientContext context) {
request = outputFilter(request, context);
if (context.getSettings().isOneway()) {
afterFilterHandler.handle(request, context);
return Promise.value(null);
}
return afterFilterHandler.handle(request, context).then(new Func() {
public ByteBuffer call(ByteBuffer response) throws Throwable {
response = inputFilter(response, context);
return response;
}
});
}
private Promise afterFilterHandler(final ByteBuffer request, final ClientContext context) {
return sendAndReceive(request, context).catchError(
new AsyncFunc() {
public Promise call(Throwable e) throws Throwable {
Promise response = retry(request, context);
if (response != null) {
return response;
}
throw e;
}
}
);
}
private Promise retry(final ByteBuffer request, final ClientContext context) throws Throwable {
InvokeSettings settings = context.getSettings();
if (settings.isFailswitch()) {
failswitch();
}
if (settings.isIdempotent() && context.retried < settings.getRetry()) {
int interval = ++context.retried * 500;
if (settings.isFailswitch()) {
interval -= (uriList.size() - 1) * 500;
}
if (interval > 5000) {
interval = 5000;
}
if (interval > 0) {
return Promise.delayed(interval, new AsyncCall() {
public Promise call() throws Throwable {
return afterFilterHandler(request, context);
}
});
}
else {
return afterFilterHandler(request, context);
}
}
return null;
}
private void failswitch() throws Throwable {
int n = uriList.size();
if (n > 1) {
if (index.compareAndSet(n - 1, 0)) {
uri = uriList.get(0);
failround++;
}
else {
uri = uriList.get(index.incrementAndGet());
}
}
else {
failround++;
}
if (onFailswitch != null) {
onFailswitch.call(this);
}
}
private ClientContext getContext(InvokeSettings settings) {
ClientContext context = new ClientContext(this);
context.getSettings().copyFrom(settings);
if (settings.getUserData() != null) {
context.getUserData().putAll(settings.getUserData());
}
return context;
}
private ByteBufferStream encode(String name, Object[] args, ClientContext context) throws Throwable {
ByteBufferStream stream = new ByteBufferStream();
InvokeSettings settings = context.getSettings();
Writer writer = new Writer(stream.getOutputStream(), mode, settings.isSimple());
stream.write(TagCall);
writer.writeString(name);
if ((args != null) && (args.length > 0 || settings.isByref())) {
writer.reset();
for (int i = 0, n = args.length; i < n; ++i) {
if (args[i] instanceof Future) {
args[i] = ((Future)args[i]).get(settings.getTimeout(), TimeUnit.MILLISECONDS);
}
}
writer.writeArray(args);
if (settings.isByref()) {
writer.writeBoolean(true);
}
}
stream.write(TagEnd);
return stream;
}
private Object getRaw(ByteBufferStream stream, Type returnType) throws HproseException {
stream.flip();
if (returnType == null ||
returnType == Object.class ||
returnType == ByteBuffer.class ||
returnType == Buffer.class) {
return stream.buffer;
}
else if (returnType == ByteBufferStream.class) {
return stream;
}
else if (returnType == byte[].class) {
byte[] bytes = stream.toArray();
stream.close();
return bytes;
}
throw new HproseException("Can't Convert ByteBuffer to Type: " + returnType.toString());
}
private Object decode(ByteBufferStream stream, Object[] args, ClientContext context) throws IOException, HproseException {
InvokeSettings settings = context.getSettings();
if (settings.isOneway()) {
return null;
}
if (stream.available() == 0) throw new HproseException("EOF");
int tag = stream.buffer.get(stream.buffer.limit() - 1);
if (tag != TagEnd) {
throw new HproseException("Wrong Response: \r\n" + StrUtil.toString(stream));
}
HproseResultMode resultMode = settings.getMode();
Type returnType = settings.getReturnType();
if (resultMode == HproseResultMode.RawWithEndTag) {
return getRaw(stream, returnType);
}
else if (resultMode == HproseResultMode.Raw) {
stream.buffer.limit(stream.buffer.limit() - 1);
return getRaw(stream, returnType);
}
Object result = null;
Reader reader = new Reader(stream.getInputStream(), mode);
tag = stream.read();
if (tag == TagResult) {
if (resultMode == HproseResultMode.Normal) {
result = reader.unserialize(returnType);
}
else if (resultMode == HproseResultMode.Serialized) {
result = getRaw(reader.readRaw(), returnType);
}
tag = stream.read();
if (tag == TagArgument) {
reader.reset();
Object[] arguments = reader.readObjectArray();
int length = args.length;
if (length > arguments.length) {
length = arguments.length;
}
System.arraycopy(arguments, 0, args, 0, length);
tag = stream.read();
}
}
else if (tag == TagError) {
throw new HproseException(reader.readString());
}
if (tag != TagEnd) {
stream.rewind();
throw new HproseException("Wrong Response: \r\n" + StrUtil.toString(stream));
}
return result;
}
@Override
protected Promise
© 2015 - 2025 Weber Informatics LLC | Privacy Policy