sncp优化
This commit is contained in:
@@ -942,7 +942,7 @@ public final class Application {
|
||||
});
|
||||
}
|
||||
if (!compileMode) {
|
||||
properties.put(SncpOldClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName());
|
||||
properties.put(OldSncpClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName());
|
||||
}
|
||||
}
|
||||
if (compileMode) {
|
||||
|
||||
@@ -291,7 +291,7 @@ public abstract class NodeServer {
|
||||
}
|
||||
|
||||
//ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory);
|
||||
SncpOldClient client = srcObj instanceof Service ? Sncp.getSncpOldClient((Service) srcObj) : null;
|
||||
OldSncpClient client = srcObj instanceof Service ? Sncp.getSncpOldClient((Service) srcObj) : null;
|
||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||
final Set<String> groups = new HashSet<>();
|
||||
Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null);
|
||||
@@ -343,7 +343,7 @@ public abstract class NodeServer {
|
||||
throw new RedkaleException("CacheSource must be inject in Service, cannot in " + srcObj);
|
||||
}
|
||||
final Service srcService = (Service) srcObj;
|
||||
SncpOldClient client = Sncp.getSncpOldClient(srcService);
|
||||
OldSncpClient client = Sncp.getSncpOldClient(srcService);
|
||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||
//final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null; //不配置SNCP服务会导致ws=false时没有注入CacheMemorySource
|
||||
final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService);
|
||||
|
||||
@@ -126,7 +126,7 @@ public class NodeSncpServer extends NodeServer {
|
||||
@Override
|
||||
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
|
||||
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
|
||||
RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName());
|
||||
RedkaleClassLoader.putReflectionPublicClasses(OldSncpDynServlet.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -75,7 +75,7 @@ public class TransportWatchService extends AbstractWatchService {
|
||||
if (!Sncp.isSncpDyn(service)) {
|
||||
continue;
|
||||
}
|
||||
SncpOldClient client = Sncp.getSncpOldClient(service);
|
||||
OldSncpClient client = Sncp.getSncpOldClient(service);
|
||||
if (Sncp.isRemote(service)) {
|
||||
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
||||
client.getRemoteGroupTransport().addRemoteAddresses(address);
|
||||
@@ -117,7 +117,7 @@ public class TransportWatchService extends AbstractWatchService {
|
||||
if (!Sncp.isSncpDyn(service)) {
|
||||
continue;
|
||||
}
|
||||
SncpOldClient client = Sncp.getSncpOldClient(service);
|
||||
OldSncpClient client = Sncp.getSncpOldClient(service);
|
||||
if (Sncp.isRemote(service)) {
|
||||
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
||||
client.getRemoteGroupTransport().removeRemoteAddresses(address);
|
||||
|
||||
@@ -55,15 +55,16 @@ public class BsonReader extends Reader {
|
||||
setBytes(bytes, start, len);
|
||||
}
|
||||
|
||||
public final void setBytes(byte[] bytes) {
|
||||
public final BsonReader setBytes(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
this.position = 0;
|
||||
} else {
|
||||
setBytes(bytes, 0, bytes.length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public final void setBytes(byte[] bytes, int start, int len) {
|
||||
public final BsonReader setBytes(byte[] bytes, int start, int len) {
|
||||
if (bytes == null) {
|
||||
this.position = 0;
|
||||
} else {
|
||||
@@ -71,6 +72,7 @@ public class BsonReader extends Reader {
|
||||
this.position = start - 1;
|
||||
//this.limit = start + len - 1;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean recycle() {
|
||||
@@ -81,8 +83,9 @@ public class BsonReader extends Reader {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.recycle();
|
||||
public BsonReader clear() {
|
||||
recycle();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -166,6 +166,11 @@ public class BsonWriter extends Writer implements ByteTuple {
|
||||
return true;
|
||||
}
|
||||
|
||||
public BsonWriter clear() {
|
||||
recycle();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + "[count=" + this.count + "]";
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
package org.redkale.mq;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.logging.*;
|
||||
import org.redkale.net.sncp.*;
|
||||
import org.redkale.util.Utility;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -31,16 +29,5 @@ public class SncpMessageRequest extends SncpRequest {
|
||||
this.createTime = System.currentTimeMillis();
|
||||
readHeader(ByteBuffer.wrap(message.getContent()), null);
|
||||
}
|
||||
|
||||
@Override //被SncpAsyncHandler.sncp_setParams调用
|
||||
protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) {
|
||||
if (message.localAttach != null) {
|
||||
return;
|
||||
}
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
message.attach(Utility.append(new Object[]{action.actionName()}, params));
|
||||
} else {
|
||||
message.attach(params);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ import org.redkale.util.*;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public final class SncpOldClient {
|
||||
public final class OldSncpClient {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(SncpOldClient.class.getSimpleName());
|
||||
protected static final Logger logger = Logger.getLogger(OldSncpClient.class.getSimpleName());
|
||||
|
||||
protected final JsonConvert convert = JsonFactory.root().getConvert();
|
||||
|
||||
@@ -70,7 +70,7 @@ public final class SncpOldClient {
|
||||
//远程模式, 可能为null
|
||||
protected Transport remoteGroupTransport;
|
||||
|
||||
public <T extends Service> SncpOldClient(final String serviceResourceName, final Class<T> serviceTypeOrImplClass, final T service, MessageAgent messageAgent, final TransportFactory factory,
|
||||
public <T extends Service> OldSncpClient(final String serviceResourceName, final Class<T> serviceTypeOrImplClass, final T service, MessageAgent messageAgent, final TransportFactory factory,
|
||||
final boolean remote, final Class serviceClass, final InetSocketAddress clientSncpAddress) {
|
||||
this.remote = remote;
|
||||
this.messageAgent = messageAgent;
|
||||
@@ -202,7 +202,7 @@ public final class SncpOldClient {
|
||||
final Attribute attr = action.paramAttrs[i];
|
||||
attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader));
|
||||
}
|
||||
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
||||
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.returnObjectType, reader);
|
||||
} catch (RpcRemoteException re) {
|
||||
throw re;
|
||||
} catch (TimeoutException e) {
|
||||
@@ -376,7 +376,7 @@ public final class SncpOldClient {
|
||||
final Attribute attr = action.paramAttrs[i];
|
||||
attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader));
|
||||
}
|
||||
Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
||||
Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.returnObjectType, reader);
|
||||
handler.completed(rs, handlerAttach);
|
||||
} catch (Exception e) {
|
||||
handler.failed(e, handlerAttach);
|
||||
727
src/main/java/org/redkale/net/sncp/OldSncpDynServlet.java
Normal file
727
src/main/java/org/redkale/net/sncp/OldSncpDynServlet.java
Normal file
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.*;
|
||||
import org.redkale.annotation.*;
|
||||
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.asm.Type;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.sncp.OldSncpHandler.DefaultSncpAsyncHandler;
|
||||
import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* public class TestService implements Service {
|
||||
*
|
||||
* public boolean change(TestBean bean, String name, int id) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* public void insert(CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* class DynActionTestService_change extends SncpServletAction {
|
||||
*
|
||||
* public TestService service;
|
||||
*
|
||||
* @Override
|
||||
public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
Object rs = service.change(arg1, arg2, arg3);
|
||||
_callParameter(out, arg1, arg2, arg3);
|
||||
convert.convertTo(out, paramTypes[0], rs);
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_insert extends SncpServletAction {
|
||||
|
||||
public TestService service;
|
||||
|
||||
@Override
|
||||
public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
OldSncpHandler arg0 = handler;
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
handler.sncp_setParams(arg0, arg1, arg2, arg3);
|
||||
service.insert(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_update extends SncpServletAction {
|
||||
|
||||
public TestService service;
|
||||
|
||||
@Override
|
||||
public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
OldSncpHandler a3 = handler;
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
|
||||
service.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DynActionTestService_changeName extends SncpServletAction {
|
||||
|
||||
public TestService service;
|
||||
|
||||
@Override
|
||||
public void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable {
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
handler.sncp_setParams(arg1, arg2, arg3);
|
||||
CompletableFuture future = service.changeName(arg1, arg2, arg3);
|
||||
handler.sncp_setFuture(future);
|
||||
}
|
||||
}
|
||||
|
||||
</pre></blockquote>
|
||||
*/
|
||||
public final class OldSncpDynServlet extends SncpServlet {
|
||||
|
||||
private final AtomicInteger maxTypeLength;
|
||||
|
||||
private final AtomicInteger maxNameLength;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(OldSncpDynServlet.class.getSimpleName());
|
||||
|
||||
private final Uint128 serviceid;
|
||||
|
||||
private final HashMap<Uint128, SncpServletAction> actions = new HashMap<>();
|
||||
|
||||
public OldSncpDynServlet(final BsonConvert convert, final String serviceResourceName, final Class serviceResourceType, final Service service,
|
||||
final AtomicInteger maxTypeLength, AtomicInteger maxNameLength) {
|
||||
super(serviceResourceName, serviceResourceType, service);
|
||||
this.maxTypeLength = maxTypeLength;
|
||||
this.maxNameLength = maxNameLength;
|
||||
this.serviceid = Sncp.serviceid(serviceResourceName, serviceResourceType);
|
||||
RedkaleClassLoader.putReflectionPublicMethods(service.getClass().getName());
|
||||
for (Map.Entry<Uint128, Method> en : Sncp.loadMethodActions(serviceResourceType).entrySet()) {
|
||||
SncpServletAction action;
|
||||
try {
|
||||
action = SncpServletAction.create(service, serviceid, en.getKey(), en.getValue());
|
||||
} catch (RuntimeException e) {
|
||||
throw new SncpException(en.getValue() + " create " + SncpServletAction.class.getSimpleName() + " error", e);
|
||||
}
|
||||
action.convert = convert;
|
||||
actions.put(en.getKey(), action);
|
||||
}
|
||||
maxNameLength.set(Math.max(maxNameLength.get(), serviceResourceName.length() + 1));
|
||||
maxTypeLength.set(Math.max(maxTypeLength.get(), serviceType.getName().length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.getClass().getSimpleName()).append(" (type=").append(serviceType.getName());
|
||||
int len = this.maxTypeLength.get() - serviceType.getName().length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(", serviceid=").append(serviceid).append(", name='").append(serviceName).append("'");
|
||||
for (int i = 0; i < this.maxNameLength.get() - serviceName.length(); i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(", actions.size=").append(actions.size() > 9 ? "" : " ").append(actions.size()).append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uint128 getServiceid() {
|
||||
return serviceid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SncpServlet other) {
|
||||
if (!(other instanceof OldSncpDynServlet)) {
|
||||
return 1;
|
||||
}
|
||||
OldSncpDynServlet o = (OldSncpDynServlet) other;
|
||||
int rs = this.serviceType.getName().compareTo(o.serviceType.getName());
|
||||
if (rs == 0) {
|
||||
rs = this.serviceName.compareTo(o.serviceName);
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute(SncpRequest request, SncpResponse response) throws IOException {
|
||||
final SncpServletAction action = actions.get(request.getHeader().getActionid());
|
||||
//logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method));
|
||||
if (action == null) {
|
||||
response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid
|
||||
} else {
|
||||
BsonWriter out = action.convert.pollBsonWriter();
|
||||
out.writePlaceholderTo(HEADER_SIZE);
|
||||
BsonReader in = action.convert.pollBsonReader();
|
||||
OldSncpHandler handler = null;
|
||||
try {
|
||||
if (action.handlerFuncParamIndex >= 0) {
|
||||
if (action.handlerFuncParamType == CompletionHandler.class) {
|
||||
handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response);
|
||||
} else {
|
||||
Creator<OldSncpHandler> creator = action.handlerCreator;
|
||||
if (creator == null) {
|
||||
creator = OldSncpHandler.Factory.createCreator(action.handlerFuncParamType);
|
||||
action.handlerCreator = creator;
|
||||
}
|
||||
handler = creator.create(new DefaultSncpAsyncHandler(logger, action, in, out, request, response));
|
||||
}
|
||||
} else if (action.boolReturnTypeFuture) {
|
||||
handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response);
|
||||
}
|
||||
in.setBytes(request.getBody());
|
||||
action.action(in, out, handler);
|
||||
if (handler == null) {
|
||||
response.finish(0, out);
|
||||
action.convert.offerBsonReader(in);
|
||||
action.convert.offerBsonWriter(out);
|
||||
} else if (action.boolReturnTypeFuture) {
|
||||
CompletableFuture future = handler.sncp_getFuture();
|
||||
if (future == null) {
|
||||
action._callParameter(out, handler.sncp_getParams());
|
||||
action.convert.convertTo(out, Object.class, null);
|
||||
} else {
|
||||
Object[] sncpParams = handler.sncp_getParams();
|
||||
future.whenComplete((v, e) -> {
|
||||
if (e != null) {
|
||||
response.getContext().getLogger().log(Level.SEVERE, "sncp CompleteAsync error(" + request + ")", e);
|
||||
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
|
||||
return;
|
||||
}
|
||||
action._callParameter(out, sncpParams);
|
||||
action.convert.convertTo(out, Object.class, v);
|
||||
response.finish(0, out);
|
||||
action.convert.offerBsonReader(in);
|
||||
action.convert.offerBsonWriter(out);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
response.getContext().getLogger().log(Level.SEVERE, "sncp execute error(" + request + ")", t);
|
||||
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class SncpServletAction {
|
||||
|
||||
public Method method;
|
||||
|
||||
public Creator<OldSncpHandler> handlerCreator;
|
||||
|
||||
protected boolean nonBlocking;
|
||||
|
||||
@Resource
|
||||
protected BsonConvert convert;
|
||||
|
||||
protected org.redkale.util.Attribute[] paramAttrs; // 为null表示无RpcCall处理,index=0固定为null, 其他为参数标记的RpcCall回调方法
|
||||
|
||||
protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type, void的返回参数类型为null
|
||||
|
||||
protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在CompletionHandler参数
|
||||
|
||||
protected Class handlerFuncParamType; //CompletionHandler参数的类型
|
||||
|
||||
protected boolean boolReturnTypeFuture = false; // 返回结果类型是否为 CompletableFuture
|
||||
|
||||
public abstract void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable;
|
||||
|
||||
//只有同步方法才调用 (没有CompletionHandler、CompletableFuture)
|
||||
public final void _callParameter(final BsonWriter out, final Object... params) {
|
||||
if (paramAttrs != null) {
|
||||
for (int i = 1; i < paramAttrs.length; i++) {
|
||||
org.redkale.util.Attribute attr = paramAttrs[i];
|
||||
if (attr == null) {
|
||||
continue;
|
||||
}
|
||||
out.writeByte((byte) i);
|
||||
convert.convertTo(out, attr.genericType(), attr.get(params[i - 1]));
|
||||
}
|
||||
}
|
||||
out.writeByte((byte) 0);
|
||||
}
|
||||
|
||||
public String actionName() {
|
||||
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* public class TestService implements Service {
|
||||
*
|
||||
* public boolean change(TestBean bean, String name, int id) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* public void insert(CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* class DynActionTestService_change extends SncpServletAction {
|
||||
*
|
||||
* public TestService service;
|
||||
*
|
||||
* @Override
|
||||
public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
Object rs = service.change(arg1, arg2, arg3);
|
||||
_callParameter(out, arg1, arg2, arg3);
|
||||
convert.convertTo(out, paramTypes[0], rs);
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_insert extends SncpServletAction {
|
||||
|
||||
public TestService service;
|
||||
|
||||
@Override
|
||||
public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
OldSncpHandler arg0 = handler;
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
handler.sncp_setParams(arg0, arg1, arg2, arg3);
|
||||
service.insert(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_update extends SncpServletAction {
|
||||
|
||||
public TestService service;
|
||||
|
||||
@Override
|
||||
public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
OldSncpHandler a3 = handler;
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
|
||||
service.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DynActionTestService_changeName extends SncpServletAction {
|
||||
|
||||
public TestService service;
|
||||
|
||||
@Override
|
||||
public void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable {
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
handler.sncp_setParams(arg1, arg2, arg3);
|
||||
CompletableFuture future = service.changeName(arg1, arg2, arg3);
|
||||
handler.sncp_setFuture(future);
|
||||
}
|
||||
}
|
||||
|
||||
</pre></blockquote>
|
||||
*
|
||||
* @param service Service
|
||||
* @param serviceid 类ID
|
||||
* @param actionid 操作ID
|
||||
* @param method 方法
|
||||
*
|
||||
* @return SncpServletAction
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static SncpServletAction create(final Service service, final Uint128 serviceid, final Uint128 actionid, final Method method) {
|
||||
final Class serviceClass = service.getClass();
|
||||
final String supDynName = SncpServletAction.class.getName().replace('.', '/');
|
||||
final String serviceName = serviceClass.getName().replace('.', '/');
|
||||
final String convertName = BsonConvert.class.getName().replace('.', '/');
|
||||
final String handlerName = OldSncpHandler.class.getName().replace('.', '/');
|
||||
final String asyncHandlerDesc = Type.getDescriptor(OldSncpHandler.class);
|
||||
final String convertReaderDesc = Type.getDescriptor(BsonReader.class);
|
||||
final String convertWriterDesc = Type.getDescriptor(BsonWriter.class);
|
||||
final String serviceDesc = Type.getDescriptor(serviceClass);
|
||||
final boolean boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + serviceClass.getName().replace('.', '_').replace('$', '_') + "__" + method.getName() + "__" + actionid;
|
||||
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncType = null;
|
||||
Class<?> newClazz = null;
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz;
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncType = paramClasses[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
|
||||
final java.lang.reflect.Type[] originalParamTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceClass);
|
||||
final java.lang.reflect.Type originalReturnType = TypeToken.getGenericType(method.getGenericReturnType(), serviceClass);
|
||||
if (newClazz == null) {
|
||||
//-------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodDebugVisitor mv;
|
||||
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
|
||||
{
|
||||
{
|
||||
fv = cw.visitField(ACC_PUBLIC, "service", serviceDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ // constructor方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
String convertFromDesc = "(Ljava/lang/reflect/Type;" + convertReaderDesc + ")Ljava/lang/Object;";
|
||||
try {
|
||||
convertFromDesc = Type.getMethodDescriptor(BsonConvert.class.getMethod("convertFrom", java.lang.reflect.Type.class, BsonReader.class));
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); //不可能会发生
|
||||
}
|
||||
{ // action方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"}));
|
||||
//mv.setDebug(true);
|
||||
int iconst = ICONST_1;
|
||||
int intconst = 1;
|
||||
int store = 4; //action的参数个数+1
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
int[][] codes = new int[paramClasses.length][2];
|
||||
for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
if (boolReturnTypeFuture) {
|
||||
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
||||
}
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one CompletionHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(paramClasses[i], method);
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncType = paramClasses[i];
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
codes[i] = new int[]{ALOAD, store};
|
||||
store++;
|
||||
iconst++;
|
||||
intconst++;
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class)));
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
mv.visitInsn(POP);
|
||||
continue;
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||
|
||||
if (intconst < 6) {
|
||||
mv.visitInsn(ICONST_0 + intconst);
|
||||
} else if (iconst <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, intconst);
|
||||
} else if (iconst <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, intconst);
|
||||
} else {
|
||||
mv.visitLdcInsn(intconst);
|
||||
}
|
||||
mv.visitInsn(AALOAD);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
int load = ALOAD;
|
||||
int v = 0;
|
||||
if (paramClasses[i].isPrimitive()) {
|
||||
int storecode = ISTORE;
|
||||
load = ILOAD;
|
||||
if (paramClasses[i] == long.class) {
|
||||
storecode = LSTORE;
|
||||
load = LLOAD;
|
||||
v = 1;
|
||||
} else if (paramClasses[i] == float.class) {
|
||||
storecode = FSTORE;
|
||||
load = FLOAD;
|
||||
v = 1;
|
||||
} else if (paramClasses[i] == double.class) {
|
||||
storecode = DSTORE;
|
||||
load = DLOAD;
|
||||
v = 1;
|
||||
}
|
||||
Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]);
|
||||
String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/');
|
||||
try {
|
||||
Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value");
|
||||
mv.visitTypeInsn(CHECKCAST, bigPrimitiveName);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); //不可能会发生
|
||||
}
|
||||
mv.visitVarInsn(storecode, store);
|
||||
} else {
|
||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store); //
|
||||
}
|
||||
codes[i] = new int[]{load, store};
|
||||
store += v;
|
||||
iconst++;
|
||||
intconst++;
|
||||
store++;
|
||||
}
|
||||
if (boolReturnTypeFuture || handlerFuncIndex >= 0) { //调用SncpAsyncHandler.setParams(Object... params)
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
if (paramClasses.length < 6) {
|
||||
mv.visitInsn(ICONST_0 + paramClasses.length);
|
||||
} else if (paramClasses.length <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, paramClasses.length);
|
||||
} else if (paramClasses.length <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, paramClasses.length);
|
||||
} else {
|
||||
mv.visitLdcInsn(paramClasses.length);
|
||||
}
|
||||
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
int insn = 3; //action的参数个数
|
||||
for (int j = 0; j < paramClasses.length; j++) {
|
||||
final Class pt = paramClasses[j];
|
||||
mv.visitInsn(DUP);
|
||||
insn++;
|
||||
if (j < 6) {
|
||||
mv.visitInsn(ICONST_0 + j);
|
||||
} else if (j <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, j);
|
||||
} else if (j <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, j);
|
||||
} else {
|
||||
mv.visitLdcInsn(j);
|
||||
}
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
Class bigclaz = TypeToken.primitiveToWrapper(pt);
|
||||
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
|
||||
}
|
||||
{ //调用service
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc);
|
||||
for (int[] j : codes) {
|
||||
mv.visitVarInsn(j[0], j[1]);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, serviceName, method.getName(), Type.getMethodDescriptor(method), false);
|
||||
}
|
||||
|
||||
final Class returnClass = method.getReturnType();
|
||||
if (returnClass != void.class) {
|
||||
if (returnClass.isPrimitive()) {
|
||||
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
||||
try {
|
||||
Method vo = bigClass.getMethod("valueOf", returnClass);
|
||||
mv.visitMethodInsn(INVOKESTATIC, bigClass.getName().replace('.', '/'), vo.getName(), Type.getMethodDescriptor(vo), false);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); //不可能会发生
|
||||
}
|
||||
}
|
||||
mv.visitVarInsn(ASTORE, store); //11
|
||||
if (boolReturnTypeFuture) {
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setFuture", "(Ljava/util/concurrent/CompletableFuture;)V", true);
|
||||
}
|
||||
}
|
||||
if (!boolReturnTypeFuture && handlerFuncIndex < 0) { //同步方法
|
||||
//------------------------- _callParameter 方法 --------------------------------
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
if (paramClasses.length < 6) { //参数总数量
|
||||
mv.visitInsn(ICONST_0 + paramClasses.length);
|
||||
} else if (paramClasses.length <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, paramClasses.length);
|
||||
} else if (paramClasses.length <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, paramClasses.length);
|
||||
} else {
|
||||
mv.visitLdcInsn(paramClasses.length);
|
||||
}
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
int insn = 3;//action的参数个数
|
||||
for (int j = 0; j < paramClasses.length; j++) {
|
||||
final Class pt = paramClasses[j];
|
||||
mv.visitInsn(DUP);
|
||||
insn++;
|
||||
if (j < 6) {
|
||||
mv.visitInsn(ICONST_0 + j);
|
||||
} else if (j <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, j);
|
||||
} else if (j <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, j);
|
||||
} else {
|
||||
mv.visitLdcInsn(j);
|
||||
}
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
Class bigclaz = TypeToken.primitiveToWrapper(pt);
|
||||
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
|
||||
}
|
||||
//-------------------------直接返回 或者 调用convertTo方法 --------------------------------
|
||||
int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1;
|
||||
if (boolReturnTypeFuture || returnClass == void.class) { //返回
|
||||
mv.visitInsn(RETURN);
|
||||
maxStack = 8;
|
||||
} else { //同步方法调用
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||
mv.visitInsn(ICONST_0);
|
||||
mv.visitInsn(AALOAD);
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertTo", "(" + convertWriterDesc + "Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
store++;
|
||||
}
|
||||
mv.visitMaxs(maxStack, store);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
byte[] bytes = cw.toByteArray();
|
||||
newClazz = new ClassLoader(serviceClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||
try {
|
||||
RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), newClazz.getField("service"));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
for (java.lang.reflect.Type t : originalParamTypes) {
|
||||
if (t.toString().startsWith("java.lang.")) {
|
||||
continue;
|
||||
}
|
||||
BsonFactory.root().loadDecoder(t);
|
||||
}
|
||||
if (originalReturnType != void.class && originalReturnType != Void.class) {
|
||||
if (boolReturnTypeFuture && method.getReturnType() != method.getGenericReturnType()) {
|
||||
java.lang.reflect.Type t = ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
|
||||
if (t != Void.class && t != java.lang.reflect.Type.class) {
|
||||
BsonFactory.root().loadEncoder(t);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
BsonFactory.root().loadEncoder(originalReturnType);
|
||||
} catch (Exception e) {
|
||||
System.err.println(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
||||
if (non == null) {
|
||||
non = service.getClass().getAnnotation(NonBlocking.class);
|
||||
}
|
||||
try {
|
||||
SncpServletAction instance = (SncpServletAction) newClazz.getDeclaredConstructor().newInstance();
|
||||
instance.method = method;
|
||||
instance.nonBlocking = non == null ? false : non.value();
|
||||
java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1];
|
||||
types[0] = originalReturnType;
|
||||
System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length);
|
||||
instance.paramTypes = types;
|
||||
instance.handlerFuncParamIndex = handlerFuncIndex;
|
||||
instance.handlerFuncParamType = handlerFuncType;
|
||||
instance.boolReturnTypeFuture = boolReturnTypeFuture;
|
||||
newClazz.getField("service").set(instance, service);
|
||||
return instance;
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); //不可能会发生
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
321
src/main/java/org/redkale/net/sncp/OldSncpHandler.java
Normal file
321
src/main/java/org/redkale/net/sncp/OldSncpHandler.java
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.*;
|
||||
import org.redkale.annotation.ConstructorParameters;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.sncp.OldSncpDynServlet.SncpServletAction;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 异步回调函数 <br>
|
||||
*
|
||||
* public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <V> 结果对象的泛型
|
||||
* @param <A> 附件对象的泛型
|
||||
*/
|
||||
public interface OldSncpHandler<V, A> extends CompletionHandler<V, A> {
|
||||
|
||||
public Object[] sncp_getParams();
|
||||
|
||||
public void sncp_setParams(Object... params);
|
||||
|
||||
public void sncp_setFuture(CompletableFuture future);
|
||||
|
||||
public CompletableFuture sncp_getFuture();
|
||||
|
||||
static class Factory {
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
|
||||
考虑点:
|
||||
1、CompletionHandler子类是接口,且还有其他多个方法
|
||||
2、CompletionHandler子类是类, 需要继承,且必须有空参数构造函数
|
||||
3、CompletionHandler子类无论是接口还是类,都可能存在其他泛型
|
||||
|
||||
public class XXXAsyncHandler_DynSncpAsyncHandler extends XXXAsyncHandler implements OldSncpHandler {
|
||||
|
||||
private OldSncpHandler sncphandler;
|
||||
|
||||
private CompletableFuture sncpfuture;
|
||||
|
||||
@ConstructorParameters({"sncphandler"})
|
||||
public XXXAsyncHandler_DynSncpAsyncHandler(OldSncpHandler sncphandler) {
|
||||
super();
|
||||
this.sncphandler = sncphandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
* public void completed(Object result, Object attachment) {
|
||||
* sncphandler.completed(result, attachment);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, Object attachment) {
|
||||
* sncphandler.failed(exc, attachment);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public Object[] sncp_getParams() {
|
||||
* return sncphandler.sncp_getParams();
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void sncp_setParams(Object... params) {
|
||||
* sncphandler.sncp_setParams(params);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void sncp_setFuture(CompletableFuture future) {
|
||||
* this.sncpfuture = future;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public CompletableFuture sncp_getFuture() {
|
||||
* return this.sncpfuture;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param handlerClass CompletionHandler类型或子类
|
||||
*
|
||||
* @return Creator
|
||||
*/
|
||||
public static Creator<OldSncpHandler> createCreator(Class<? extends CompletionHandler> handlerClass) {
|
||||
//-------------------------------------------------------------
|
||||
final boolean handlerinterface = handlerClass.isInterface();
|
||||
final String handlerClassName = handlerClass.getName().replace('.', '/');
|
||||
final String sncpHandlerName = OldSncpHandler.class.getName().replace('.', '/');
|
||||
final String cpDesc = Type.getDescriptor(ConstructorParameters.class);
|
||||
final String sncpHandlerDesc = Type.getDescriptor(OldSncpHandler.class);
|
||||
final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class);
|
||||
final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + OldSncpHandler.class.getSimpleName()
|
||||
+ "__" + handlerClass.getName().replace('.', '/').replace('$', '_');
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz;
|
||||
return Creator.create(newHandlerClazz);
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
// ------------------------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodDebugVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName});
|
||||
|
||||
{ //handler 属性
|
||||
fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ //future 属性
|
||||
fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{//构造方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + sncpHandlerDesc + ")V", null, null));
|
||||
//mv.setDebug(true);
|
||||
{
|
||||
av0 = mv.visitAnnotation(cpDesc, true);
|
||||
{
|
||||
AnnotationVisitor av1 = av0.visitArray("value");
|
||||
av1.visit(null, "sncphandler");
|
||||
av1.visitEnd();
|
||||
}
|
||||
av0.visitEnd();
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
|
||||
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
|
||||
Class returnType = method.getReturnType();
|
||||
if (returnType == void.class) {
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
} else if (returnType.isPrimitive()) {
|
||||
mv.visitInsn(ICONST_0);
|
||||
if (returnType == long.class) {
|
||||
mv.visitInsn(LRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == float.class) {
|
||||
mv.visitInsn(FRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == double.class) {
|
||||
mv.visitInsn(DRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else {
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
} else {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
{ // sncp_getParams
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // sncp_setParams
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // sncp_setFuture
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // sncp_getFuture
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class<OldSncpHandler> newClazz = (Class<OldSncpHandler>) new ClassLoader(handlerClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
return Creator.create(newClazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DefaultSncpAsyncHandler<V, A> implements OldSncpHandler<V, A> {
|
||||
|
||||
//为了在回调函数中调用_callParameter方法
|
||||
protected Object[] params;
|
||||
|
||||
protected SncpServletAction action;
|
||||
|
||||
protected BsonReader in;
|
||||
|
||||
protected BsonWriter out;
|
||||
|
||||
protected SncpRequest request;
|
||||
|
||||
protected SncpResponse response;
|
||||
|
||||
protected CompletableFuture future;
|
||||
|
||||
protected Logger logger;
|
||||
|
||||
public DefaultSncpAsyncHandler(Logger logger, SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) {
|
||||
this.logger = logger;
|
||||
this.action = action;
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
try {
|
||||
action._callParameter(out, sncp_getParams());
|
||||
action.convert.convertTo(out, Object.class, result);
|
||||
response.finish(0, out);
|
||||
} catch (Exception e) {
|
||||
failed(e, attachment);
|
||||
} finally {
|
||||
action.convert.offerBsonReader(in);
|
||||
action.convert.offerBsonWriter(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
response.getContext().getLogger().log(Level.INFO, "Sncp execute error(" + request + ")", exc);
|
||||
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] sncp_getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sncp_setParams(Object... params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sncp_setFuture(CompletableFuture future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture sncp_getFuture() {
|
||||
return this.future;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -249,14 +249,14 @@ public abstract class Sncp {
|
||||
}
|
||||
}
|
||||
|
||||
public static SncpOldClient getSncpOldClient(Service service) {
|
||||
public static OldSncpClient getSncpOldClient(Service service) {
|
||||
if (service == null || !isSncpDyn(service)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_client");
|
||||
ts.setAccessible(true);
|
||||
return (SncpOldClient) ts.get(service);
|
||||
return (OldSncpClient) ts.get(service);
|
||||
} catch (Exception e) {
|
||||
throw new SncpException(service + " not found " + FIELDPREFIX + "_client");
|
||||
}
|
||||
@@ -299,7 +299,7 @@ public abstract class Sncp {
|
||||
if (!isSncpDyn(service)) {
|
||||
return false;
|
||||
}
|
||||
SncpOldClient client = getSncpOldClient(service);
|
||||
OldSncpClient client = getSncpOldClient(service);
|
||||
client.setRemoteGroups(groups);
|
||||
if (client.getRemoteGroupTransport() != null) {
|
||||
client.getRemoteGroupTransport().updateRemoteAddresses(addresses);
|
||||
@@ -340,18 +340,10 @@ public abstract class Sncp {
|
||||
throw new SncpException(param + " must have a empty parameter Constructor");
|
||||
}
|
||||
for (Method m : param.getMethods()) {
|
||||
if (m.getName().equals("completed") && Modifier.isFinal(m.getModifiers())) {
|
||||
if (m.getName().equals("completed") && m.getParameterCount() == 2 && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new SncpException(param + "'s completed method cannot final modifier");
|
||||
} else if (m.getName().equals("failed") && Modifier.isFinal(m.getModifiers())) {
|
||||
} else if (m.getName().equals("failed") && m.getParameterCount() == 2 && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new SncpException(param + "'s failed method cannot final modifier");
|
||||
} else if (m.getName().equals("sncp_getParams") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new SncpException(param + "'s sncp_getParams method cannot final modifier");
|
||||
} else if (m.getName().equals("sncp_setParams") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new SncpException(param + "'s sncp_setParams method cannot final modifier");
|
||||
} else if (m.getName().equals("sncp_setFuture") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new SncpException(param + "'s sncp_setFuture method cannot final modifier");
|
||||
} else if (m.getName().equals("sncp_getFuture") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new SncpException(param + "'s sncp_getFuture method cannot final modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +367,54 @@ public abstract class Sncp {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
//获取一个clazz内所有未被实现的方法
|
||||
public static List<Method> loadNotImplMethods(Class clazz) {
|
||||
LinkedHashSet<Class> types = new LinkedHashSet<>();
|
||||
loadAllSubClasses(clazz, types);
|
||||
List<Method> methods = new ArrayList<>();
|
||||
Set<String> ms = new HashSet<>();
|
||||
for (Class c : types) {
|
||||
for (Method m : c.getDeclaredMethods()) {
|
||||
if (c.isInterface() || Modifier.isAbstract(m.getModifiers())) {
|
||||
StringBuilder sb = new StringBuilder(); //不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致
|
||||
sb.append(m.getName());
|
||||
sb.append('(');
|
||||
boolean first = true;
|
||||
for (Class pt : m.getParameterTypes()) {
|
||||
if (!first) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(pt.getName());
|
||||
first = false;
|
||||
}
|
||||
sb.append(')');
|
||||
String key = sb.toString();
|
||||
Uint128 a = actionid(m);
|
||||
if (!ms.contains(key)) {
|
||||
methods.add(m);
|
||||
ms.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
private static void loadAllSubClasses(Class clazz, LinkedHashSet<Class> types) {
|
||||
if (clazz == null || clazz == Object.class) {
|
||||
return;
|
||||
}
|
||||
types.add(clazz);
|
||||
if (clazz.getSuperclass() != null) {
|
||||
loadAllSubClasses(clazz.getSuperclass(), types);
|
||||
}
|
||||
if (clazz.getInterfaces() != null) {
|
||||
for (Class sub : clazz.getInterfaces()) {
|
||||
loadAllSubClasses(sub, types);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* public class TestService implements Service{
|
||||
@@ -403,7 +443,7 @@ public abstract class Sncp {
|
||||
*
|
||||
* private AnyValue _redkale_conf;
|
||||
*
|
||||
* private SncpOldClient _redkale_client;
|
||||
* private OldSncpClient _redkale_client;
|
||||
*
|
||||
* @Override
|
||||
* public String toString() {
|
||||
@@ -436,9 +476,9 @@ public abstract class Sncp {
|
||||
throw new SncpException(serviceImplClass + " is abstract");
|
||||
}
|
||||
final String supDynName = serviceImplClass.getName().replace('.', '/');
|
||||
final String clientName = SncpOldClient.class.getName().replace('.', '/');
|
||||
final String clientName = OldSncpClient.class.getName().replace('.', '/');
|
||||
final String resDesc = Type.getDescriptor(Resource.class);
|
||||
final String clientDesc = Type.getDescriptor(SncpOldClient.class);
|
||||
final String clientDesc = Type.getDescriptor(OldSncpClient.class);
|
||||
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
|
||||
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
|
||||
ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
|
||||
@@ -481,7 +521,7 @@ public abstract class Sncp {
|
||||
av0.visit("type", Type.getType(Type.getDescriptor(getResourceType(serviceImplClass))));
|
||||
av0.visitEnd();
|
||||
}
|
||||
{ //给新类加上 原有的Annotation
|
||||
{ //给新类加上原有的Annotation
|
||||
for (Annotation ann : serviceImplClass.getAnnotations()) {
|
||||
if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) {
|
||||
continue;
|
||||
@@ -623,12 +663,12 @@ public abstract class Sncp {
|
||||
}
|
||||
} while ((loop = loop.getSuperclass()) != Object.class);
|
||||
}
|
||||
SncpOldClient client = null;
|
||||
OldSncpClient client = null;
|
||||
{
|
||||
try {
|
||||
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
|
||||
c.setAccessible(true);
|
||||
client = new SncpOldClient(name, serviceImplClass, service, messageAgent, transportFactory, false, newClazz, clientSncpAddress);
|
||||
client = new OldSncpClient(name, serviceImplClass, service, messageAgent, transportFactory, false, newClazz, clientSncpAddress);
|
||||
c.set(service, client);
|
||||
if (transportFactory != null) {
|
||||
transportFactory.addSncpService(service);
|
||||
@@ -677,7 +717,7 @@ public abstract class Sncp {
|
||||
*
|
||||
* private AnyValue _redkale_conf;
|
||||
*
|
||||
* private SncpOldClient _redkale_client;
|
||||
* private OldSncpClient _redkale_client;
|
||||
*
|
||||
* @Override
|
||||
* public void createSomeThing(TestBean bean){
|
||||
@@ -735,9 +775,9 @@ public abstract class Sncp {
|
||||
return null;
|
||||
}
|
||||
final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/');
|
||||
final String clientName = SncpOldClient.class.getName().replace('.', '/');
|
||||
final String clientName = OldSncpClient.class.getName().replace('.', '/');
|
||||
final String resDesc = Type.getDescriptor(Resource.class);
|
||||
final String clientDesc = Type.getDescriptor(SncpOldClient.class);
|
||||
final String clientDesc = Type.getDescriptor(OldSncpClient.class);
|
||||
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
|
||||
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
|
||||
final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
|
||||
@@ -747,7 +787,7 @@ public abstract class Sncp {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz;
|
||||
T service = (T) newClazz.getDeclaredConstructor().newInstance();
|
||||
SncpOldClient client = new SncpOldClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
|
||||
OldSncpClient client = new OldSncpClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
|
||||
client.setRemoteGroups(groups);
|
||||
if (transportFactory != null) {
|
||||
client.setRemoteGroupTransport(transportFactory.loadTransport(clientAddress, groups));
|
||||
@@ -803,7 +843,7 @@ public abstract class Sncp {
|
||||
av0.visit("type", Type.getType(Type.getDescriptor(serviceTypeOrImplClass)));
|
||||
av0.visitEnd();
|
||||
}
|
||||
{ //给新类加上 原有的Annotation
|
||||
{ //给新类加上原有的Annotation
|
||||
for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) {
|
||||
if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) {
|
||||
continue;
|
||||
@@ -972,7 +1012,7 @@ public abstract class Sncp {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||
try {
|
||||
T service = (T) newClazz.getDeclaredConstructor().newInstance();
|
||||
SncpOldClient client = new SncpOldClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
|
||||
OldSncpClient client = new OldSncpClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
|
||||
client.setRemoteGroups(groups);
|
||||
if (transportFactory != null) {
|
||||
client.setRemoteGroupTransport(transportFactory.loadTransport(clientAddress, groups));
|
||||
|
||||
@@ -1,322 +1,203 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.*;
|
||||
import org.redkale.annotation.ConstructorParameters;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.sncp.SncpDynServlet.SncpServletAction;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 异步回调函数 <br>
|
||||
*
|
||||
* public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <V> 结果对象的泛型
|
||||
* @param <A> 附件对象的泛型
|
||||
*/
|
||||
public interface SncpAsyncHandler<V, A> extends CompletionHandler<V, A> {
|
||||
|
||||
public Object[] sncp_getParams();
|
||||
|
||||
public void sncp_setParams(Object... params);
|
||||
|
||||
public void sncp_setFuture(CompletableFuture future);
|
||||
|
||||
public CompletableFuture sncp_getFuture();
|
||||
|
||||
static class Factory {
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* 考虑点:
|
||||
* 1、CompletionHandler子类是接口,且还有其他多个方法
|
||||
* 2、CompletionHandler子类是类, 需要继承,且必须有空参数构造函数
|
||||
* 3、CompletionHandler子类无论是接口还是类,都可能存在其他泛型
|
||||
*
|
||||
* public class XXXAsyncHandler_DynSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler {
|
||||
*
|
||||
* private SncpAsyncHandler sncphandler;
|
||||
*
|
||||
* private CompletableFuture sncpfuture;
|
||||
*
|
||||
* @ConstructorParameters({"sncphandler"})
|
||||
* public XXXAsyncHandler_DynSncpAsyncHandler(SncpAsyncHandler sncphandler) {
|
||||
* super();
|
||||
* this.sncphandler = sncphandler;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void completed(Object result, Object attachment) {
|
||||
* sncphandler.completed(result, attachment);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, Object attachment) {
|
||||
* sncphandler.failed(exc, attachment);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public Object[] sncp_getParams() {
|
||||
* return sncphandler.sncp_getParams();
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void sncp_setParams(Object... params) {
|
||||
* sncphandler.sncp_setParams(params);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void sncp_setFuture(CompletableFuture future) {
|
||||
* this.sncpfuture = future;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public CompletableFuture sncp_getFuture() {
|
||||
* return this.sncpfuture;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param handlerClass CompletionHandler类型或子类
|
||||
*
|
||||
* @return Creator
|
||||
*/
|
||||
public static Creator<SncpAsyncHandler> createCreator(Class<? extends CompletionHandler> handlerClass) {
|
||||
//-------------------------------------------------------------
|
||||
final boolean handlerinterface = handlerClass.isInterface();
|
||||
final String handlerClassName = handlerClass.getName().replace('.', '/');
|
||||
final String sncpHandlerName = SncpAsyncHandler.class.getName().replace('.', '/');
|
||||
final String cpDesc = Type.getDescriptor(ConstructorParameters.class);
|
||||
final String sncpHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class);
|
||||
final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class);
|
||||
final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + SncpAsyncHandler.class.getSimpleName()
|
||||
+ "__" + handlerClass.getName().replace('.', '/').replace('$', '_');
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz;
|
||||
return Creator.create(newHandlerClazz);
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
// ------------------------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodDebugVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName});
|
||||
|
||||
{ //handler 属性
|
||||
fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ //future 属性
|
||||
fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{//构造方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + sncpHandlerDesc + ")V", null, null));
|
||||
//mv.setDebug(true);
|
||||
{
|
||||
av0 = mv.visitAnnotation(cpDesc, true);
|
||||
{
|
||||
AnnotationVisitor av1 = av0.visitArray("value");
|
||||
av1.visit(null, "sncphandler");
|
||||
av1.visitEnd();
|
||||
}
|
||||
av0.visitEnd();
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
|
||||
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
|
||||
Class returnType = method.getReturnType();
|
||||
if (returnType == void.class) {
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
} else if (returnType.isPrimitive()) {
|
||||
mv.visitInsn(ICONST_0);
|
||||
if (returnType == long.class) {
|
||||
mv.visitInsn(LRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == float.class) {
|
||||
mv.visitInsn(FRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == double.class) {
|
||||
mv.visitInsn(DRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else {
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
} else {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
{ // sncp_getParams
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // sncp_setParams
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // sncp_setFuture
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // sncp_getFuture
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class<SncpAsyncHandler> newClazz = (Class<SncpAsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
return Creator.create(newClazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DefaultSncpAsyncHandler<V, A> implements SncpAsyncHandler<V, A> {
|
||||
|
||||
//为了在回调函数中调用_callParameter方法
|
||||
protected Object[] params;
|
||||
|
||||
protected SncpServletAction action;
|
||||
|
||||
protected BsonReader in;
|
||||
|
||||
protected BsonWriter out;
|
||||
|
||||
protected SncpRequest request;
|
||||
|
||||
protected SncpResponse response;
|
||||
|
||||
protected CompletableFuture future;
|
||||
|
||||
protected Logger logger;
|
||||
|
||||
public DefaultSncpAsyncHandler(Logger logger, SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) {
|
||||
this.logger = logger;
|
||||
this.action = action;
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
try {
|
||||
action._callParameter(out, sncp_getParams());
|
||||
action.convert.convertTo(out, Object.class, result);
|
||||
response.finish(0, out);
|
||||
} catch (Exception e) {
|
||||
failed(e, attachment);
|
||||
} finally {
|
||||
action.convert.offerBsonReader(in);
|
||||
action.convert.offerBsonWriter(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
response.getContext().getLogger().log(Level.INFO, "Sncp execute error(" + request + ")", exc);
|
||||
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] sncp_getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sncp_setParams(Object... params) {
|
||||
this.params = params;
|
||||
this.request.sncp_setParams(this.action, this.logger, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sncp_setFuture(CompletableFuture future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture sncp_getFuture() {
|
||||
return this.future;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.Opcodes.ACC_FINAL;
|
||||
import static org.redkale.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.redkale.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.redkale.asm.Opcodes.ACC_SUPER;
|
||||
import static org.redkale.asm.Opcodes.ACONST_NULL;
|
||||
import static org.redkale.asm.Opcodes.ALOAD;
|
||||
import static org.redkale.asm.Opcodes.ARETURN;
|
||||
import static org.redkale.asm.Opcodes.DRETURN;
|
||||
import static org.redkale.asm.Opcodes.FRETURN;
|
||||
import static org.redkale.asm.Opcodes.GETFIELD;
|
||||
import static org.redkale.asm.Opcodes.ICONST_0;
|
||||
import static org.redkale.asm.Opcodes.INVOKEINTERFACE;
|
||||
import static org.redkale.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.redkale.asm.Opcodes.IRETURN;
|
||||
import static org.redkale.asm.Opcodes.LRETURN;
|
||||
import static org.redkale.asm.Opcodes.PUTFIELD;
|
||||
import static org.redkale.asm.Opcodes.RETURN;
|
||||
import static org.redkale.asm.Opcodes.V11;
|
||||
import org.redkale.asm.Type;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 异步回调函数
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <V> 结果对象的泛型
|
||||
* @param <A> 附件对象的泛型
|
||||
*
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public interface SncpAsyncHandler<V, A> extends CompletionHandler<V, A> {
|
||||
|
||||
public static SncpAsyncHandler createHandler(Class<? extends CompletionHandler> handlerClazz, CompletionHandler realHandler) {
|
||||
Objects.requireNonNull(handlerClazz);
|
||||
Objects.requireNonNull(realHandler);
|
||||
if (handlerClazz == CompletionHandler.class) {
|
||||
return new SncpAsyncHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
realHandler.completed(result, attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
realHandler.failed(exc, attachment);
|
||||
}
|
||||
};
|
||||
}
|
||||
return HandlerInner.creatorMap.computeIfAbsent(handlerClazz, handlerClass -> {
|
||||
//-------------------------------------------------------------
|
||||
final boolean handlerInterface = handlerClass.isInterface();
|
||||
final Class sncpHandlerClass = SncpAsyncHandler.class;
|
||||
final String handlerClassName = handlerClass.getName().replace('.', '/');
|
||||
final String sncpHandlerName = sncpHandlerClass.getName().replace('.', '/');
|
||||
final String cpDesc = Type.getDescriptor(org.redkale.annotation.ConstructorParameters.class);
|
||||
final String realHandlerName = CompletionHandler.class.getName().replace('.', '/');
|
||||
final String realHandlerDesc = Type.getDescriptor(CompletionHandler.class);
|
||||
final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + sncpHandlerClass.getSimpleName()
|
||||
+ "__" + handlerClass.getName().replace('.', '/').replace('$', '_');
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz;
|
||||
return (Creator<SncpAsyncHandler>) Creator.create(newHandlerClazz);
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
// ------------------------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodDebugVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerInterface ? "java/lang/Object" : handlerClassName, handlerInterface && handlerClass != sncpHandlerClass ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName});
|
||||
|
||||
{ //handler 属性
|
||||
fv = cw.visitField(ACC_PRIVATE, "realHandler", realHandlerDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{//构造方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + realHandlerDesc + ")V", null, null));
|
||||
//mv.setDebug(true);
|
||||
{
|
||||
av0 = mv.visitAnnotation(cpDesc, true);
|
||||
{
|
||||
AnnotationVisitor av1 = av0.visitArray("value");
|
||||
av1.visit(null, "realHandler");
|
||||
av1.visitEnd();
|
||||
}
|
||||
av0.visitEnd();
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, handlerInterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "realHandler", realHandlerDesc);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
for (Method method : Sncp.loadNotImplMethods(handlerClass)) { //
|
||||
int mod = method.getModifiers();
|
||||
String methodDesc = Type.getMethodDescriptor(method);
|
||||
if (Modifier.isPublic(mod) && "completed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", methodDesc, null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "realHandler", realHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, realHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
// if (!"(Ljava/lang/Object;Ljava/lang/Object;)V".equals(methodDesc)) {
|
||||
// mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null));
|
||||
// mv.visitVarInsn(ALOAD, 0);
|
||||
// mv.visitVarInsn(ALOAD, 1);
|
||||
// mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
|
||||
// mv.visitVarInsn(ALOAD, 2);
|
||||
// mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
|
||||
// mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "completed", methodDesc, false);
|
||||
// mv.visitInsn(RETURN);
|
||||
// mv.visitMaxs(3, 3);
|
||||
// mv.visitEnd();
|
||||
// }
|
||||
} else if (Modifier.isPublic(mod) && "failed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", methodDesc, null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "realHandler", realHandlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, realHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
// if (!"(Ljava/lang/Throwable;Ljava/lang/Object;)V".equals(methodDesc)) {
|
||||
// mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", null, null));
|
||||
// mv.visitVarInsn(ALOAD, 0);
|
||||
// mv.visitVarInsn(ALOAD, 1);
|
||||
// mv.visitVarInsn(ALOAD, 2);
|
||||
// mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
|
||||
// mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "failed", methodDesc, false);
|
||||
// mv.visitInsn(RETURN);
|
||||
// mv.visitMaxs(3, 3);
|
||||
// mv.visitEnd();
|
||||
// }
|
||||
} else if (handlerInterface || Modifier.isAbstract(mod)) {
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
|
||||
Class returnType = method.getReturnType();
|
||||
if (returnType == void.class) {
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
} else if (returnType.isPrimitive()) {
|
||||
mv.visitInsn(ICONST_0);
|
||||
if (returnType == long.class) {
|
||||
mv.visitInsn(LRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == float.class) {
|
||||
mv.visitInsn(FRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == double.class) {
|
||||
mv.visitInsn(DRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else {
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
} else {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
cw.visitEnd();
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class newClazz = new ClassLoader((handlerClass != CompletionHandler.class ? handlerClass : sncpHandlerClass).getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
return (Creator<SncpAsyncHandler>) Creator.create(newClazz);
|
||||
}).create(realHandler);
|
||||
}
|
||||
|
||||
static class HandlerInner {
|
||||
|
||||
static final Map<Class, Creator<SncpAsyncHandler>> creatorMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.redkale.util.*;
|
||||
*/
|
||||
public class SncpDispatcherServlet extends DispatcherServlet<Uint128, SncpContext, SncpRequest, SncpResponse, SncpServlet> {
|
||||
|
||||
private final ReentrantLock sncplock = new ReentrantLock();
|
||||
private final ReentrantLock updateLock = new ReentrantLock();
|
||||
|
||||
private final byte[] pongBytes = Sncp.getPongBytes();
|
||||
|
||||
@@ -30,7 +30,7 @@ public class SncpDispatcherServlet extends DispatcherServlet<Uint128, SncpContex
|
||||
|
||||
@Override
|
||||
public void addServlet(SncpServlet servlet, Object attachment, AnyValue conf, Uint128... mappings) {
|
||||
sncplock.lock();
|
||||
updateLock.lock();
|
||||
try {
|
||||
for (SncpServlet s : getServlets()) {
|
||||
if (s.service == servlet.service) {
|
||||
@@ -41,13 +41,13 @@ public class SncpDispatcherServlet extends DispatcherServlet<Uint128, SncpContex
|
||||
putMapping(servlet.getServiceid(), servlet);
|
||||
putServlet(servlet);
|
||||
} finally {
|
||||
sncplock.unlock();
|
||||
updateLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> SncpServlet removeSncpServlet(Service service) {
|
||||
SncpServlet rs = null;
|
||||
sncplock.lock();
|
||||
updateLock.lock();
|
||||
try {
|
||||
for (SncpServlet servlet : getServlets()) {
|
||||
if (servlet.service == service) {
|
||||
@@ -60,7 +60,7 @@ public class SncpDispatcherServlet extends DispatcherServlet<Uint128, SncpContex
|
||||
removeServlet(rs);
|
||||
}
|
||||
} finally {
|
||||
sncplock.unlock();
|
||||
updateLock.unlock();
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
@@ -9,17 +9,15 @@ import java.io.IOException;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.*;
|
||||
import org.redkale.annotation.*;
|
||||
import java.util.logging.Level;
|
||||
import org.redkale.annotation.NonBlocking;
|
||||
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.asm.Type;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.sncp.SncpAsyncHandler.DefaultSncpAsyncHandler;
|
||||
import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.*;
|
||||
|
||||
@@ -36,31 +34,28 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
|
||||
private final AtomicInteger maxNameLength;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SncpDynServlet.class.getSimpleName());
|
||||
|
||||
private final Uint128 serviceid;
|
||||
|
||||
private final HashMap<Uint128, SncpServletAction> actions = new HashMap<>();
|
||||
private final HashMap<Uint128, SncpActionServlet> actions = new HashMap<>();
|
||||
|
||||
public SncpDynServlet(final BsonConvert convert, final String serviceResourceName, final Class serviceResourceType, final Service service,
|
||||
public SncpDynServlet(final String resourceName, final Class resourceType, final Service service,
|
||||
final AtomicInteger maxTypeLength, AtomicInteger maxNameLength) {
|
||||
super(serviceResourceName, serviceResourceType, service);
|
||||
super(resourceName, resourceType, service);
|
||||
this.maxTypeLength = maxTypeLength;
|
||||
this.maxNameLength = maxNameLength;
|
||||
this.serviceid = Sncp.serviceid(serviceResourceName, serviceResourceType);
|
||||
this.serviceid = Sncp.serviceid(resourceName, resourceType);
|
||||
RedkaleClassLoader.putReflectionPublicMethods(service.getClass().getName());
|
||||
for (Map.Entry<Uint128, Method> en : Sncp.loadMethodActions(serviceResourceType).entrySet()) {
|
||||
SncpServletAction action;
|
||||
for (Map.Entry<Uint128, Method> en : Sncp.loadMethodActions(resourceType).entrySet()) {
|
||||
SncpActionServlet action;
|
||||
try {
|
||||
action = SncpServletAction.create(service, serviceid, en.getKey(), en.getValue());
|
||||
action = SncpActionServlet.create(resourceName, resourceType, service, serviceid, en.getKey(), en.getValue());
|
||||
} catch (RuntimeException e) {
|
||||
throw new SncpException(en.getValue() + " create " + SncpServletAction.class.getSimpleName() + " error", e);
|
||||
throw new SncpException(en.getValue() + " create " + SncpActionServlet.class.getSimpleName() + " error", e);
|
||||
}
|
||||
action.convert = convert;
|
||||
actions.put(en.getKey(), action);
|
||||
}
|
||||
maxNameLength.set(Math.max(maxNameLength.get(), serviceResourceName.length() + 1));
|
||||
maxTypeLength.set(Math.max(maxTypeLength.get(), serviceType.getName().length()));
|
||||
maxNameLength.set(Math.max(maxNameLength.get(), resourceName.length() + 1));
|
||||
maxTypeLength.set(Math.max(maxTypeLength.get(), resourceType.getName().length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,11 +80,11 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SncpServlet o0) {
|
||||
if (!(o0 instanceof SncpDynServlet)) {
|
||||
public int compareTo(SncpServlet other) {
|
||||
if (!(other instanceof OldSncpDynServlet)) {
|
||||
return 1;
|
||||
}
|
||||
SncpDynServlet o = (SncpDynServlet) o0;
|
||||
OldSncpDynServlet o = (OldSncpDynServlet) other;
|
||||
int rs = this.serviceType.getName().compareTo(o.serviceType.getName());
|
||||
if (rs == 0) {
|
||||
rs = this.serviceName.compareTo(o.serviceName);
|
||||
@@ -100,56 +95,28 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute(SncpRequest request, SncpResponse response) throws IOException {
|
||||
final SncpServletAction action = actions.get(request.getHeader().getActionid());
|
||||
final SncpActionServlet action = actions.get(request.getHeader().getActionid());
|
||||
//logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method));
|
||||
if (action == null) {
|
||||
response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid
|
||||
} else {
|
||||
BsonWriter out = action.convert.pollBsonWriter();
|
||||
out.writePlaceholderTo(HEADER_SIZE);
|
||||
BsonReader in = action.convert.pollBsonReader();
|
||||
SncpAsyncHandler handler = null;
|
||||
try {
|
||||
if (action.handlerFuncParamIndex >= 0) {
|
||||
if (action.handlerFuncParamType == CompletionHandler.class) {
|
||||
handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response);
|
||||
if (response.inNonBlocking()) {
|
||||
if (action.nonBlocking) {
|
||||
action.execute(request, response);
|
||||
} else {
|
||||
Creator<SncpAsyncHandler> creator = action.handlerCreator;
|
||||
if (creator == null) {
|
||||
creator = SncpAsyncHandler.Factory.createCreator(action.handlerFuncParamType);
|
||||
action.handlerCreator = creator;
|
||||
}
|
||||
handler = creator.create(new DefaultSncpAsyncHandler(logger, action, in, out, request, response));
|
||||
}
|
||||
} else if (action.boolReturnTypeFuture) {
|
||||
handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response);
|
||||
}
|
||||
in.setBytes(request.getBody());
|
||||
action.action(in, out, handler);
|
||||
if (handler == null) {
|
||||
response.finish(0, out);
|
||||
action.convert.offerBsonReader(in);
|
||||
action.convert.offerBsonWriter(out);
|
||||
} else if (action.boolReturnTypeFuture) {
|
||||
CompletableFuture future = handler.sncp_getFuture();
|
||||
if (future == null) {
|
||||
action._callParameter(out, handler.sncp_getParams());
|
||||
action.convert.convertTo(out, Object.class, null);
|
||||
} else {
|
||||
Object[] sncpParams = handler.sncp_getParams();
|
||||
future.whenComplete((v, e) -> {
|
||||
if (e != null) {
|
||||
response.getContext().getLogger().log(Level.SEVERE, "sncp CompleteAsync error(" + request + ")", e);
|
||||
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
|
||||
return;
|
||||
response.updateNonBlocking(false);
|
||||
response.getWorkExecutor().execute(() -> {
|
||||
try {
|
||||
action.execute(request, response);
|
||||
} catch (Throwable t) {
|
||||
response.getContext().getLogger().log(Level.WARNING, "Servlet occur exception. request = " + request, t);
|
||||
response.finishError(t);
|
||||
}
|
||||
action._callParameter(out, sncpParams);
|
||||
action.convert.convertTo(out, Object.class, v);
|
||||
response.finish(0, out);
|
||||
action.convert.offerBsonReader(in);
|
||||
action.convert.offerBsonWriter(out);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
action.execute(request, response);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
response.getContext().getLogger().log(Level.SEVERE, "sncp execute error(" + request + ")", t);
|
||||
@@ -158,42 +125,114 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class SncpServletAction {
|
||||
public static abstract class SncpActionServlet extends SncpServlet {
|
||||
|
||||
public Method method;
|
||||
protected final Method method;
|
||||
|
||||
public Creator<SncpAsyncHandler> handlerCreator;
|
||||
protected final Uint128 serviceid;
|
||||
|
||||
protected boolean nonBlocking;
|
||||
protected final Uint128 actionid;
|
||||
|
||||
@Resource
|
||||
protected BsonConvert convert;
|
||||
protected final boolean nonBlocking;
|
||||
|
||||
protected org.redkale.util.Attribute[] paramAttrs; // 为null表示无RpcCall处理,index=0固定为null, 其他为参数标记的RpcCall回调方法
|
||||
protected final java.lang.reflect.Type[] paramTypes; //第一个元素存放返回类型return type, void的返回参数类型为null, 数组长度为:1+参数个数
|
||||
|
||||
protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type, void的返回参数类型为null
|
||||
protected final java.lang.reflect.Type returnObjectType; //返回结果的CompletableFuture的结果泛型类型
|
||||
|
||||
protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在CompletionHandler参数
|
||||
protected final int paramHandlerIndex; //>=0表示存在CompletionHandler参数
|
||||
|
||||
protected Class handlerFuncParamType; //CompletionHandler参数的类型
|
||||
protected final Class<? extends CompletionHandler> paramHandlerType; //CompletionHandler参数的类型
|
||||
|
||||
protected boolean boolReturnTypeFuture = false; // 返回结果类型是否为 CompletableFuture
|
||||
protected final java.lang.reflect.Type paramHandlerResultType; //CompletionHandler.completed第一个参数的类型
|
||||
|
||||
public abstract void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable;
|
||||
protected final java.lang.reflect.Type returnFutureResultType; //返回结果的CompletableFuture的结果泛型类型
|
||||
|
||||
//只有同步方法才调用 (没有CompletionHandler、CompletableFuture)
|
||||
public final void _callParameter(final BsonWriter out, final Object... params) {
|
||||
if (paramAttrs != null) {
|
||||
for (int i = 1; i < paramAttrs.length; i++) {
|
||||
org.redkale.util.Attribute attr = paramAttrs[i];
|
||||
if (attr == null) {
|
||||
continue;
|
||||
protected SncpActionServlet(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
super(resourceName, resourceType, service);
|
||||
this.serviceid = serviceid;
|
||||
this.actionid = actionid;
|
||||
this.method = method;
|
||||
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncType = null;
|
||||
java.lang.reflect.Type handlerResultType = null;
|
||||
try {
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncType = paramClasses[i];
|
||||
java.lang.reflect.Type handlerType = TypeToken.getGenericType(method.getTypeParameters()[i], service.getClass());
|
||||
if (handlerType instanceof Class) {
|
||||
handlerResultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
handlerResultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
} else {
|
||||
throw new SncpException(service.getClass() + " had unknown gGenericType in " + method);
|
||||
}
|
||||
break;
|
||||
}
|
||||
out.writeByte((byte) i);
|
||||
convert.convertTo(out, attr.genericType(), attr.get(params[i - 1]));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
out.writeByte((byte) 0);
|
||||
java.lang.reflect.Type[] originalParamTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), service.getClass());
|
||||
java.lang.reflect.Type originalReturnType = TypeToken.getGenericType(method.getGenericReturnType(), service.getClass());
|
||||
java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1];
|
||||
types[0] = originalReturnType;
|
||||
System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length);
|
||||
this.paramTypes = types;
|
||||
this.paramHandlerIndex = handlerFuncIndex;
|
||||
this.paramHandlerType = handlerFuncType;
|
||||
this.paramHandlerResultType = handlerResultType;
|
||||
this.returnObjectType = originalReturnType;
|
||||
if (CompletionStage.class.isAssignableFrom(method.getReturnType())) {
|
||||
java.lang.reflect.Type futureType = TypeToken.getGenericType(method.getGenericReturnType(), service.getClass());
|
||||
java.lang.reflect.Type returnType = null;
|
||||
if (futureType instanceof Class) {
|
||||
returnType = Object.class;
|
||||
} else if (futureType instanceof ParameterizedType) {
|
||||
returnType = TypeToken.getGenericType(((ParameterizedType) futureType).getActualTypeArguments()[0], futureType);
|
||||
} else {
|
||||
throw new SncpException(service.getClass() + " had unknown return genericType in " + method);
|
||||
}
|
||||
this.returnFutureResultType = returnType;
|
||||
} else {
|
||||
this.returnFutureResultType = null;
|
||||
}
|
||||
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
||||
if (non == null) {
|
||||
non = service.getClass().getAnnotation(NonBlocking.class);
|
||||
}
|
||||
this.nonBlocking = non == null ? (CompletionStage.class.isAssignableFrom(method.getReturnType()) || this.paramHandlerIndex >= 0) : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(SncpRequest request, SncpResponse response) throws IOException {
|
||||
if (paramHandlerIndex > 0) {
|
||||
response.paramAsyncHandler(paramHandlerType, paramHandlerResultType);
|
||||
}
|
||||
try {
|
||||
action(request, response);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void action(SncpRequest request, SncpResponse response) throws Throwable;
|
||||
|
||||
public <T extends Service> T service() {
|
||||
return (T) service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uint128 getServiceid() {
|
||||
return serviceid;
|
||||
}
|
||||
|
||||
public Uint128 getActionid() {
|
||||
return actionid;
|
||||
}
|
||||
|
||||
public String actionName() {
|
||||
@@ -225,103 +264,104 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
* public TestService service;
|
||||
*
|
||||
* @Override
|
||||
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* Object rs = service.change(arg1, arg2, arg3);
|
||||
* _callParameter(out, arg1, arg2, arg3);
|
||||
* convert.convertTo(out, paramTypes[0], rs);
|
||||
* }
|
||||
* public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* Object rs = service.change(arg1, arg2, arg3);
|
||||
* _callParameter(out, arg1, arg2, arg3);
|
||||
* convert.convertTo(out, paramTypes[0], rs);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_insert extends SncpServletAction {
|
||||
*
|
||||
* public TestService service;
|
||||
* public TestService service;
|
||||
*
|
||||
* @Override
|
||||
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
|
||||
* SncpAsyncHandler arg0 = handler;
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* handler.sncp_setParams(arg0, arg1, arg2, arg3);
|
||||
* service.insert(arg0, arg1, arg2, arg3);
|
||||
* }
|
||||
* @Override
|
||||
* public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
* OldSncpHandler arg0 = handler;
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* handler.sncp_setParams(arg0, arg1, arg2, arg3);
|
||||
* service.insert(arg0, arg1, arg2, arg3);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_update extends SncpServletAction {
|
||||
*
|
||||
* public TestService service;
|
||||
* public TestService service;
|
||||
*
|
||||
* @Override
|
||||
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
|
||||
* long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
* short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
* SncpAsyncHandler a3 = handler;
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
|
||||
* service.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* }
|
||||
* @Override
|
||||
* public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
|
||||
* long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
* short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
* OldSncpHandler a3 = handler;
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
|
||||
* service.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* class DynActionTestService_changeName extends SncpServletAction {
|
||||
*
|
||||
* public TestService service;
|
||||
* public TestService service;
|
||||
*
|
||||
* @Override
|
||||
* public void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable {
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* handler.sncp_setParams(arg1, arg2, arg3);
|
||||
* CompletableFuture future = service.changeName(arg1, arg2, arg3);
|
||||
* handler.sncp_setFuture(future);
|
||||
* }
|
||||
* @Override
|
||||
* public void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable {
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* handler.sncp_setParams(arg1, arg2, arg3);
|
||||
* CompletableFuture future = service.changeName(arg1, arg2, arg3);
|
||||
* handler.sncp_setFuture(future);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param service Service
|
||||
* @param serviceid 类ID
|
||||
* @param actionid 操作ID
|
||||
* @param method 方法
|
||||
* @param resourceName 资源名
|
||||
* @param resourceType 资源类
|
||||
* @param service Service
|
||||
* @param serviceid 类ID
|
||||
* @param actionid 操作ID
|
||||
* @param method 方法
|
||||
*
|
||||
* @return SncpServletAction
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static SncpServletAction create(final Service service, final Uint128 serviceid, final Uint128 actionid, final Method method) {
|
||||
final Class serviceClass = service.getClass();
|
||||
final String supDynName = SncpServletAction.class.getName().replace('.', '/');
|
||||
final String serviceName = serviceClass.getName().replace('.', '/');
|
||||
final String convertName = BsonConvert.class.getName().replace('.', '/');
|
||||
final String handlerName = SncpAsyncHandler.class.getName().replace('.', '/');
|
||||
final String asyncHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class);
|
||||
final String convertReaderDesc = Type.getDescriptor(BsonReader.class);
|
||||
final String convertWriterDesc = Type.getDescriptor(BsonWriter.class);
|
||||
final String serviceDesc = Type.getDescriptor(serviceClass);
|
||||
final boolean boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + serviceClass.getName().replace('.', '_').replace('$', '_') + "__" + method.getName() + "__" + actionid;
|
||||
public static SncpActionServlet create(
|
||||
final String resourceName,
|
||||
final Class resourceType,
|
||||
final Service service,
|
||||
final Uint128 serviceid,
|
||||
final Uint128 actionid,
|
||||
final Method method) {
|
||||
|
||||
final Class serviceClass = service.getClass();
|
||||
final String supDynName = SncpActionServlet.class.getName().replace('.', '/');
|
||||
final String resourceTypeName = resourceType.getName().replace('.', '/');
|
||||
final String convertName = BsonConvert.class.getName().replace('.', '/');
|
||||
final String uint128Desc = Type.getDescriptor(Uint128.class);
|
||||
final String convertDesc = Type.getDescriptor(BsonConvert.class);
|
||||
final String bsonReaderDesc = Type.getDescriptor(BsonReader.class);
|
||||
final String requestName = SncpRequest.class.getName().replace('.', '/');
|
||||
final String responseName = SncpResponse.class.getName().replace('.', '/');
|
||||
final String requestDesc = Type.getDescriptor(SncpRequest.class);
|
||||
final String responseDesc = Type.getDescriptor(SncpResponse.class);
|
||||
final boolean boolReturnTypeFuture = CompletionStage.class.isAssignableFrom(method.getReturnType());
|
||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
||||
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncType = null;
|
||||
Class<?> newClazz = null;
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz;
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncType = paramClasses[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
|
||||
@@ -335,34 +375,44 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
|
||||
{
|
||||
{
|
||||
fv = cw.visitField(ACC_PUBLIC, "service", serviceDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ // constructor方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;Ljava/lang/Class;Lorg/redkale/service/Service;" + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitVarInsn(ALOAD, 5);
|
||||
mv.visitVarInsn(ALOAD, 6);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "(Ljava/lang/String;Ljava/lang/Class;Lorg/redkale/service/Service;" + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitMaxs(7, 7);
|
||||
mv.visitEnd();
|
||||
}
|
||||
String convertFromDesc = "(Ljava/lang/reflect/Type;" + convertReaderDesc + ")Ljava/lang/Object;";
|
||||
String convertFromDesc = "(Ljava/lang/reflect/Type;" + bsonReaderDesc + ")Ljava/lang/Object;";
|
||||
try {
|
||||
convertFromDesc = Type.getMethodDescriptor(BsonConvert.class.getMethod("convertFrom", java.lang.reflect.Type.class, BsonReader.class));
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); //不可能会发生
|
||||
}
|
||||
{ // action方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"}));
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/lang/Throwable"}));
|
||||
//mv.setDebug(true);
|
||||
{ //BsonConvert
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getBsonConvert", "()" + convertDesc, false);
|
||||
mv.visitVarInsn(ASTORE, 3);
|
||||
}
|
||||
{ //BsonReader
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getBsonReader", "()" + bsonReaderDesc, false);
|
||||
mv.visitVarInsn(ASTORE, 4);
|
||||
}
|
||||
int iconst = ICONST_1;
|
||||
int intconst = 1;
|
||||
int store = 4; //action的参数个数+1
|
||||
int store = 5; //action的参数个数+2
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
int[][] codes = new int[paramClasses.length][2];
|
||||
int handlerFuncIndex = -1;
|
||||
for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
if (boolReturnTypeFuture) {
|
||||
@@ -373,24 +423,22 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
Sncp.checkAsyncModifier(paramClasses[i], method);
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncType = paramClasses[i];
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "getParamAsyncHandler", "()Ljava/nio/channels/CompletionHandler;", false);
|
||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
codes[i] = new int[]{ALOAD, store};
|
||||
store++;
|
||||
iconst++;
|
||||
intconst++;
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class)));
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
mv.visitInsn(POP);
|
||||
continue;
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||
|
||||
@@ -404,7 +452,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
mv.visitLdcInsn(intconst);
|
||||
}
|
||||
mv.visitInsn(AALOAD);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
int load = ALOAD;
|
||||
@@ -445,63 +493,21 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
intconst++;
|
||||
store++;
|
||||
}
|
||||
if (boolReturnTypeFuture || handlerFuncIndex >= 0) { //调用SncpAsyncHandler.setParams(Object... params)
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
if (paramClasses.length < 6) {
|
||||
mv.visitInsn(ICONST_0 + paramClasses.length);
|
||||
} else if (paramClasses.length <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, paramClasses.length);
|
||||
} else if (paramClasses.length <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, paramClasses.length);
|
||||
} else {
|
||||
mv.visitLdcInsn(paramClasses.length);
|
||||
}
|
||||
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
int insn = 3; //action的参数个数
|
||||
for (int j = 0; j < paramClasses.length; j++) {
|
||||
final Class pt = paramClasses[j];
|
||||
mv.visitInsn(DUP);
|
||||
insn++;
|
||||
if (j < 6) {
|
||||
mv.visitInsn(ICONST_0 + j);
|
||||
} else if (j <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, j);
|
||||
} else if (j <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, j);
|
||||
} else {
|
||||
mv.visitLdcInsn(j);
|
||||
}
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
Class bigclaz = TypeToken.primitiveToWrapper(pt);
|
||||
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
|
||||
}
|
||||
{ //调用service
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()Lorg/redkale/service/Service;", false);
|
||||
mv.visitTypeInsn(CHECKCAST, resourceTypeName);
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
for (int[] j : codes) {
|
||||
mv.visitVarInsn(j[0], j[1]);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, serviceName, method.getName(), Type.getMethodDescriptor(method), false);
|
||||
mv.visitMethodInsn(resourceType.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, resourceTypeName, method.getName(), Type.getMethodDescriptor(method), resourceType.isInterface());
|
||||
store++;
|
||||
}
|
||||
|
||||
final Class returnClass = method.getReturnType();
|
||||
if (returnClass != void.class) {
|
||||
if (method.getReturnType() != void.class) {
|
||||
final Class returnClass = method.getReturnType();
|
||||
if (returnClass.isPrimitive()) {
|
||||
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
||||
try {
|
||||
@@ -512,78 +518,29 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
}
|
||||
mv.visitVarInsn(ASTORE, store); //11
|
||||
if (boolReturnTypeFuture) {
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
|
||||
if (boolReturnTypeFuture) { //返回类型为CompletionStage
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;");
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setFuture", "(Ljava/util/concurrent/CompletableFuture;)V", true);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishFuture", "(Ljava/lang/reflect/Type;Ljava/util/concurrent/CompletionStage;)V", false);
|
||||
} else if (handlerFuncIndex >= 0) { //参数有CompletionHandler
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||
} else { //普通对象
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", "Ljava/lang/reflect/Type;");
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finish", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false);
|
||||
}
|
||||
}
|
||||
if (!boolReturnTypeFuture && handlerFuncIndex < 0) { //同步方法
|
||||
//------------------------- _callParameter 方法 --------------------------------
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
} else { //void返回类型
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
if (paramClasses.length < 6) { //参数总数量
|
||||
mv.visitInsn(ICONST_0 + paramClasses.length);
|
||||
} else if (paramClasses.length <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, paramClasses.length);
|
||||
} else if (paramClasses.length <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, paramClasses.length);
|
||||
} else {
|
||||
mv.visitLdcInsn(paramClasses.length);
|
||||
}
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
int insn = 3;//action的参数个数
|
||||
for (int j = 0; j < paramClasses.length; j++) {
|
||||
final Class pt = paramClasses[j];
|
||||
mv.visitInsn(DUP);
|
||||
insn++;
|
||||
if (j < 6) {
|
||||
mv.visitInsn(ICONST_0 + j);
|
||||
} else if (j <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, j);
|
||||
} else if (j <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, j);
|
||||
} else {
|
||||
mv.visitLdcInsn(j);
|
||||
}
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
Class bigclaz = TypeToken.primitiveToWrapper(pt);
|
||||
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||
}
|
||||
//-------------------------直接返回 或者 调用convertTo方法 --------------------------------
|
||||
int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1;
|
||||
if (boolReturnTypeFuture || returnClass == void.class) { //返回
|
||||
mv.visitInsn(RETURN);
|
||||
maxStack = 8;
|
||||
} else { //同步方法调用
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||
mv.visitInsn(ICONST_0);
|
||||
mv.visitInsn(AALOAD);
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertTo", "(" + convertWriterDesc + "Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
store++;
|
||||
}
|
||||
mv.visitMaxs(maxStack, store);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(8, store);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
@@ -621,23 +578,9 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
}
|
||||
}
|
||||
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
||||
if (non == null) {
|
||||
non = service.getClass().getAnnotation(NonBlocking.class);
|
||||
}
|
||||
try {
|
||||
SncpServletAction instance = (SncpServletAction) newClazz.getDeclaredConstructor().newInstance();
|
||||
instance.method = method;
|
||||
instance.nonBlocking = non == null ? false : non.value();
|
||||
java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1];
|
||||
types[0] = originalReturnType;
|
||||
System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length);
|
||||
instance.paramTypes = types;
|
||||
instance.handlerFuncParamIndex = handlerFuncIndex;
|
||||
instance.handlerFuncParamType = handlerFuncType;
|
||||
instance.boolReturnTypeFuture = boolReturnTypeFuture;
|
||||
newClazz.getField("service").set(instance, service);
|
||||
return instance;
|
||||
return (SncpActionServlet) newClazz.getConstructors()[0]
|
||||
.newInstance(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); //不可能会发生
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ package org.redkale.net.sncp;
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.*;
|
||||
import java.util.logging.Level;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.Request;
|
||||
import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE;
|
||||
import org.redkale.util.Uint128;
|
||||
@@ -30,6 +31,8 @@ public class SncpRequest extends Request<SncpContext> {
|
||||
|
||||
protected static final int READ_STATE_END = 4;
|
||||
|
||||
protected final BsonReader reader = new BsonReader();
|
||||
|
||||
protected int readState = READ_STATE_ROUTE;
|
||||
|
||||
private SncpHeader header;
|
||||
@@ -61,6 +64,10 @@ public class SncpRequest extends Request<SncpContext> {
|
||||
context.getLogger().log(Level.WARNING, "sncp buffer header.retcode not 0");
|
||||
return -1;
|
||||
}
|
||||
if (this.header.getBodyLength() > context.getMaxBody()) {
|
||||
context.getLogger().log(Level.WARNING, "sncp buffer body.length must lower " + context.getMaxBody() + ", but " + this.header.getBodyLength());
|
||||
return -1;
|
||||
}
|
||||
this.body = new byte[this.header.getBodyLength()];
|
||||
this.readState = READ_STATE_BODY;
|
||||
}
|
||||
@@ -98,10 +105,6 @@ public class SncpRequest extends Request<SncpContext> {
|
||||
this.keepAlive = true;
|
||||
}
|
||||
|
||||
//被SncpAsyncHandler.sncp_setParams调用
|
||||
protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return SncpRequest.class.getSimpleName() + "_" + Objects.hashCode(this) + "{header=" + this.header + ",bodyOffset=" + this.bodyOffset + ",body=[" + (this.body == null ? -1 : this.body.length) + "]}";
|
||||
@@ -109,6 +112,7 @@ public class SncpRequest extends Request<SncpContext> {
|
||||
|
||||
@Override
|
||||
protected void recycle() {
|
||||
this.reader.clear();
|
||||
this.readState = READ_STATE_ROUTE;
|
||||
this.header = null;
|
||||
this.bodyOffset = 0;
|
||||
@@ -121,6 +125,14 @@ public class SncpRequest extends Request<SncpContext> {
|
||||
return ping;
|
||||
}
|
||||
|
||||
public BsonConvert getBsonConvert() {
|
||||
return context.getBsonConvert();
|
||||
}
|
||||
|
||||
public BsonReader getBsonReader() {
|
||||
return body == null ? null : reader.setBytes(body);
|
||||
}
|
||||
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.*;
|
||||
import org.redkale.convert.bson.BsonWriter;
|
||||
import org.redkale.net.Response;
|
||||
import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE;
|
||||
@@ -32,6 +34,24 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
|
||||
private final int addrPort;
|
||||
|
||||
protected final BsonWriter writer = new BsonWriter();
|
||||
|
||||
protected final CompletionHandler realHandler = new CompletionHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
finish(paramHandlerResultType, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
finishError(exc);
|
||||
}
|
||||
};
|
||||
|
||||
protected Type paramHandlerResultType;
|
||||
|
||||
protected CompletionHandler paramAsyncHandler;
|
||||
|
||||
public static String getRetCodeInfo(int retcode) {
|
||||
if (retcode == RETCODE_ILLSERVICEID) {
|
||||
return "The serviceid is invalid";
|
||||
@@ -57,6 +77,16 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
}
|
||||
}
|
||||
|
||||
public SncpResponse paramAsyncHandler(Class<? extends CompletionHandler> paramHandlerType, Type paramHandlerResultType) {
|
||||
this.paramHandlerResultType = paramHandlerResultType;
|
||||
this.paramAsyncHandler = paramHandlerType == CompletionHandler.class ? realHandler : SncpAsyncHandler.createHandler(paramHandlerType, realHandler);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T extends CompletionHandler> T getParamAsyncHandler() {
|
||||
return (T) this.paramAsyncHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepare() {
|
||||
super.prepare();
|
||||
@@ -64,9 +94,16 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
|
||||
@Override
|
||||
protected boolean recycle() {
|
||||
writer.clear();
|
||||
this.paramHandlerResultType = null;
|
||||
this.paramAsyncHandler = null;
|
||||
return super.recycle();
|
||||
}
|
||||
|
||||
public BsonWriter getBsonWriter() {
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExecutorService getWorkExecutor() {
|
||||
return super.getWorkExecutor();
|
||||
@@ -92,6 +129,36 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
finish(RETCODE_THROWEXCEPTION, null);
|
||||
}
|
||||
|
||||
public final void finishVoid() {
|
||||
BsonWriter out = getBsonWriter();
|
||||
out.writePlaceholderTo(HEADER_SIZE);
|
||||
finish(0, out);
|
||||
}
|
||||
|
||||
public final void finishFuture(final Type futureResultType, final CompletionStage future) {
|
||||
if (future == null) {
|
||||
finishVoid();
|
||||
} else {
|
||||
future.whenComplete((v, t) -> {
|
||||
if (t != null) {
|
||||
finishError((Throwable) t);
|
||||
} else {
|
||||
finish(futureResultType, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public final void finish(final Type type, final Object result) {
|
||||
BsonWriter out = getBsonWriter();
|
||||
out.writePlaceholderTo(HEADER_SIZE);
|
||||
if (result != null || type != Void.class) {
|
||||
out.writeByte((byte) 0); //body的第一个字节为0,表示返回结果对象,而不是参数回调对象
|
||||
context.getBsonConvert().convertTo(out, type, result);
|
||||
}
|
||||
finish(0, out);
|
||||
}
|
||||
|
||||
//调用此方法时out已写入SncpHeader
|
||||
public void finish(final int retcode, final BsonWriter out) {
|
||||
if (out == null) {
|
||||
@@ -101,7 +168,8 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
return;
|
||||
}
|
||||
final ByteArray array = out.toByteArray();
|
||||
fillHeader(array, array.length() - HEADER_SIZE, retcode);
|
||||
final int bodyLength = array.length() - HEADER_SIZE;
|
||||
fillHeader(array, bodyLength, retcode);
|
||||
finish(array);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ package org.redkale.net.sncp;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import org.redkale.boot.Application;
|
||||
import org.redkale.convert.bson.BsonFactory;
|
||||
import org.redkale.net.Server;
|
||||
import org.redkale.net.sncp.SncpContext.SncpContextConfig;
|
||||
import org.redkale.service.Service;
|
||||
@@ -28,7 +27,7 @@ public class SncpServer extends Server<Uint128, SncpContext, SncpRequest, SncpRe
|
||||
private final AtomicInteger maxTypeLength = new AtomicInteger();
|
||||
|
||||
private final AtomicInteger maxNameLength = new AtomicInteger();
|
||||
|
||||
|
||||
public SncpServer() {
|
||||
this(null, System.currentTimeMillis(), null, ResourceFactory.create());
|
||||
}
|
||||
@@ -108,7 +107,7 @@ public class SncpServer extends Server<Uint128, SncpContext, SncpRequest, SncpRe
|
||||
if (!Sncp.isSncpDyn(sncpService)) {
|
||||
throw new SncpException(sncpService + " is not sncp dynamic-gen service");
|
||||
}
|
||||
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), Sncp.getResourceName(sncpService),
|
||||
SncpDynServlet sds = new SncpDynServlet(Sncp.getResourceName(sncpService),
|
||||
Sncp.getResourceType(sncpService), sncpService, maxTypeLength, maxNameLength);
|
||||
this.dispatcher.addServlet(sds, null, Sncp.getResourceConf(sncpService));
|
||||
return sds;
|
||||
|
||||
@@ -118,7 +118,7 @@ public final class SncpServiceInfo<T extends Service> {
|
||||
|
||||
protected final Method method;
|
||||
|
||||
protected final Type resultTypes; //void 必须设为 null
|
||||
protected final Type returnObjectType; //void 必须设为 null
|
||||
|
||||
protected final Type[] paramTypes;
|
||||
|
||||
@@ -146,7 +146,7 @@ public final class SncpServiceInfo<T extends Service> {
|
||||
SncpServiceAction(final Class serviceImplClass, Method method, Uint128 serviceid, Uint128 actionid) {
|
||||
this.actionid = actionid == null ? Sncp.actionid(method) : actionid;
|
||||
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass);
|
||||
this.resultTypes = rt == void.class ? null : rt;
|
||||
this.returnObjectType = rt == void.class ? null : rt;
|
||||
this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
||||
this.futureCreator = boolReturnTypeFuture ? Creator.create((Class<? extends CompletableFuture>) method.getReturnType()) : null;
|
||||
this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass);
|
||||
|
||||
@@ -26,9 +26,9 @@ public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, Sncp
|
||||
|
||||
protected final Service service;
|
||||
|
||||
protected SncpServlet(String serviceResourceName, Class serviceResourceType, Service service) {
|
||||
this.serviceName = serviceResourceName;
|
||||
this.serviceType = serviceResourceType;
|
||||
protected SncpServlet(String resourceName, Class resourceType, Service service) {
|
||||
this.serviceName = resourceName;
|
||||
this.serviceType = resourceType;
|
||||
this.service = service;
|
||||
this._nonBlocking = true;
|
||||
}
|
||||
|
||||
@@ -270,16 +270,16 @@ public abstract class TypeToken<T> {
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param type 泛型
|
||||
* @param paramType 泛型
|
||||
* @param declaringClass 泛型依附类
|
||||
*
|
||||
* @return Type
|
||||
*/
|
||||
public static Type getGenericType(final Type type, final Type declaringClass) {
|
||||
if (type == null || declaringClass == null) {
|
||||
return type;
|
||||
public static Type getGenericType(final Type paramType, final Type declaringClass) {
|
||||
if (paramType == null || declaringClass == null) {
|
||||
return paramType;
|
||||
}
|
||||
if (type instanceof TypeVariable) {
|
||||
if (paramType instanceof TypeVariable) {
|
||||
Type superType = null;
|
||||
Class declaringClass0 = null;
|
||||
if (declaringClass instanceof Class) {
|
||||
@@ -288,7 +288,7 @@ public abstract class TypeToken<T> {
|
||||
if (superType instanceof ParameterizedType) {
|
||||
Map<Type, Type> map = new HashMap<>();
|
||||
parseType(map, declaringClass0);
|
||||
Type rstype = getType(map, type);
|
||||
Type rstype = getType(map, paramType);
|
||||
if (rstype instanceof Class) {
|
||||
return rstype;
|
||||
}
|
||||
@@ -314,7 +314,7 @@ public abstract class TypeToken<T> {
|
||||
if (atas.length == asts.length) {
|
||||
for (int i = 0; i < asts.length; i++) {
|
||||
Type currt = asts[i];
|
||||
if (asts[i] != type && superPT.getRawType() instanceof Class) {
|
||||
if (asts[i] != paramType && superPT.getRawType() instanceof Class) {
|
||||
if (asts[i] instanceof TypeVariable) {
|
||||
|
||||
Class raw = (Class) superPT.getRawType();
|
||||
@@ -345,24 +345,24 @@ public abstract class TypeToken<T> {
|
||||
} while (raw != Object.class);
|
||||
}
|
||||
}
|
||||
if (currt == type) {
|
||||
if (currt == paramType) {
|
||||
if (atas[i] instanceof Class
|
||||
&& ((TypeVariable) type).getBounds().length == 1
|
||||
&& ((TypeVariable) type).getBounds()[0] instanceof Class
|
||||
&& ((Class) ((TypeVariable) type).getBounds()[0]).isAssignableFrom((Class) atas[i])) {
|
||||
&& ((TypeVariable) paramType).getBounds().length == 1
|
||||
&& ((TypeVariable) paramType).getBounds()[0] instanceof Class
|
||||
&& ((Class) ((TypeVariable) paramType).getBounds()[0]).isAssignableFrom((Class) atas[i])) {
|
||||
return atas[i];
|
||||
}
|
||||
if (atas[i] instanceof Class
|
||||
&& ((TypeVariable) type).getBounds().length == 1
|
||||
&& ((TypeVariable) type).getBounds()[0] instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) ((TypeVariable) type).getBounds()[0];
|
||||
&& ((TypeVariable) paramType).getBounds().length == 1
|
||||
&& ((TypeVariable) paramType).getBounds()[0] instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) ((TypeVariable) paramType).getBounds()[0];
|
||||
if (pt.getRawType() instanceof Class && ((Class) pt.getRawType()).isAssignableFrom((Class) atas[i])) {
|
||||
return atas[i];
|
||||
}
|
||||
}
|
||||
if (atas[i] instanceof ParameterizedType
|
||||
&& ((TypeVariable) type).getBounds().length == 1
|
||||
&& ((TypeVariable) type).getBounds()[0] == Object.class) {
|
||||
&& ((TypeVariable) paramType).getBounds().length == 1
|
||||
&& ((TypeVariable) paramType).getBounds()[0] == Object.class) {
|
||||
return atas[i];
|
||||
}
|
||||
}
|
||||
@@ -372,7 +372,7 @@ public abstract class TypeToken<T> {
|
||||
TypeVariable[] argTypes = ((Class) cycType.getRawType()).getTypeParameters();
|
||||
if (argTypes.length == asts.length) {
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
if (argTypes[i] == type) {
|
||||
if (argTypes[i] == paramType) {
|
||||
if (atas[i] instanceof TypeVariable
|
||||
&& ((TypeVariable) atas[i]).getBounds().length == 1
|
||||
&& ((TypeVariable) atas[i]).getBounds()[0] instanceof Class) {
|
||||
@@ -385,24 +385,24 @@ public abstract class TypeToken<T> {
|
||||
}
|
||||
Type moreType = ((ParameterizedType) superType).getRawType();
|
||||
if (moreType != Object.class) {
|
||||
return getGenericType(type, moreType);
|
||||
return getGenericType(paramType, moreType);
|
||||
}
|
||||
}
|
||||
TypeVariable tv = (TypeVariable) type;
|
||||
TypeVariable tv = (TypeVariable) paramType;
|
||||
if (tv.getBounds().length == 1) {
|
||||
return tv.getBounds()[0];
|
||||
}
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
final Type rst = getGenericType(((GenericArrayType) type).getGenericComponentType(), declaringClass);
|
||||
} else if (paramType instanceof GenericArrayType) {
|
||||
final Type rst = getGenericType(((GenericArrayType) paramType).getGenericComponentType(), declaringClass);
|
||||
return (GenericArrayType) () -> rst;
|
||||
}
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) type;
|
||||
if (paramType instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) paramType;
|
||||
return createParameterizedType(getGenericType(pt.getOwnerType(), declaringClass),
|
||||
getGenericType(pt.getRawType(), declaringClass),
|
||||
getGenericType(pt.getActualTypeArguments(), declaringClass));
|
||||
}
|
||||
return type;
|
||||
return paramType;
|
||||
}
|
||||
|
||||
private static Type getType(Map<Type, Type> map, Type type) {
|
||||
|
||||
97
src/test/java/org/redkale/test/sncp/SncpHandlerTest.java
Normal file
97
src/test/java/org/redkale/test/sncp/SncpHandlerTest.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.test.sncp;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.redkale.net.sncp.SncpAsyncHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class SncpHandlerTest {
|
||||
|
||||
private boolean main;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SncpHandlerTest test = new SncpHandlerTest();
|
||||
test.main = true;
|
||||
test.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() throws Exception {
|
||||
SncpAsyncHandler.createHandler(CompletionHandler.class, new CompletionHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
if (main) {
|
||||
System.out.println("handler result: " + result + ", attachment: " + attachment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
|
||||
}
|
||||
}).completed(1, 2);
|
||||
|
||||
SncpAsyncHandler.createHandler(ITestHandler1.class, new CompletionHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
System.out.println("handler1 result: " + result + ", attachment: " + attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
|
||||
}
|
||||
}).completed("name", "/user/");
|
||||
|
||||
SncpAsyncHandler.createHandler(ITestHandler2.class, new CompletionHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
System.out.println("handler2 result: " + result + ", attachment: " + attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
|
||||
}
|
||||
}).completed("aaa", "bbb");
|
||||
|
||||
SncpAsyncHandler.createHandler(ITestHandler3.class, new CompletionHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
System.out.println("handler3 result: " + result + ", attachment: " + attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
|
||||
}
|
||||
}).completed("key1", "val1");
|
||||
}
|
||||
|
||||
public static abstract class ITestHandler1 implements CompletionHandler<String, File> {
|
||||
|
||||
@Override
|
||||
public abstract void completed(String result, File attachment);
|
||||
}
|
||||
|
||||
public static interface IClose<T> {
|
||||
|
||||
public void close(T val);
|
||||
}
|
||||
|
||||
public static interface ITestHandler2 extends CompletionHandler<String, String>, IClose<File> {
|
||||
|
||||
}
|
||||
|
||||
public static interface ITestHandler3 extends CompletionHandler<String, String>, Map<String, String> {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -163,6 +163,7 @@ public class SncpTest {
|
||||
conf.addValue("host", "0.0.0.0");
|
||||
conf.addValue("port", "" + port);
|
||||
conf.addValue("protocol", protocol);
|
||||
conf.addValue("maxbody", "" + (100 * 1024 * 1024));
|
||||
SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory);
|
||||
Set<InetSocketAddress> set = new LinkedHashSet<>();
|
||||
if (port2 > 0) {
|
||||
@@ -203,6 +204,7 @@ public class SncpTest {
|
||||
conf.addValue("host", "0.0.0.0");
|
||||
conf.addValue("port", "" + (port2 < 10 ? 0 : port2));
|
||||
conf.addValue("protocol", protocol);
|
||||
conf.addValue("maxbody", "" + (100 * 1024 * 1024));
|
||||
SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory);
|
||||
Set<InetSocketAddress> set = new LinkedHashSet<>();
|
||||
set.add(new InetSocketAddress(myhost, port));
|
||||
|
||||
146
src/test/java/org/redkale/test/sncp/TestService.java
Normal file
146
src/test/java/org/redkale/test/sncp/TestService.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.test.sncp;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.redkale.annotation.ResourceType;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.sncp.SncpDynServlet.SncpActionServlet;
|
||||
import org.redkale.net.sncp.*;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public interface TestService extends Service {
|
||||
|
||||
public boolean change(TestBean bean, String name, int id);
|
||||
|
||||
public void insert(BooleanHandler handler, TestBean bean, String name, int id);
|
||||
|
||||
public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||
|
||||
public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||
|
||||
@ResourceType(TestService.class)
|
||||
public static class TestServiceImpl implements TestService {
|
||||
|
||||
@Override
|
||||
public boolean change(TestBean bean, String name, int id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
|
||||
|
||||
@Override
|
||||
public void completed(Boolean result, TestBean attachment) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, TestBean attachment) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DynActionTestService_change extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
BsonConvert convert = request.getBsonConvert();
|
||||
BsonReader in = request.getBsonReader();
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
Object rs = serviceObj.change(arg1, arg2, arg3);
|
||||
response.finish(boolean.class, rs);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynActionTestService_insert extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
BsonConvert convert = request.getBsonConvert();
|
||||
BsonReader in = request.getBsonReader();
|
||||
BooleanHandler arg0 = response.getParamAsyncHandler();
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.insert(arg0, arg1, arg2, arg3);
|
||||
response.finishVoid();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynActionTestService_update extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
BsonConvert convert = request.getBsonConvert();
|
||||
BsonReader in = request.getBsonReader();
|
||||
long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
CompletionHandler a3 = response.getParamAsyncHandler();
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
response.finishVoid();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynActionTestService_changeName extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
BsonConvert convert = request.getBsonConvert();
|
||||
BsonReader in = request.getBsonReader();
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||
response.finishFuture(paramHandlerResultType, future);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
package org.redkale.test.sncp;
|
||||
|
||||
import org.redkale.net.sncp.*;
|
||||
import org.redkale.annotation.ResourceType;
|
||||
|
||||
/**
|
||||
@@ -15,6 +14,5 @@ import org.redkale.annotation.ResourceType;
|
||||
@ResourceType(SncpTestIService.class)
|
||||
public class _DynLocalSncpTestService extends SncpTestServiceImpl {
|
||||
|
||||
private SncpOldClient _redkale_client;
|
||||
|
||||
}
|
||||
|
||||
74
src/test/java/org/redkale/test/util/TypeTokenTest.java
Normal file
74
src/test/java/org/redkale/test/util/TypeTokenTest.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.test.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.redkale.util.TypeToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class TypeTokenTest {
|
||||
|
||||
private boolean main;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
TypeTokenTest test = new TypeTokenTest();
|
||||
test.main = true;
|
||||
test.run();
|
||||
test.run2();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() throws Exception {
|
||||
Class serviceType = Service1.class;
|
||||
Method method = serviceType.getMethod("test", String.class, CompletionHandler.class);
|
||||
Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType);
|
||||
Type resultType = null;
|
||||
if (handlerType instanceof Class) {
|
||||
resultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
resultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
}
|
||||
if (!main) {
|
||||
Assertions.assertEquals(resultType, String.class);
|
||||
}
|
||||
System.out.println("resultType = " + resultType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run2() throws Exception {
|
||||
Class serviceType = Service2.class;
|
||||
Method method = serviceType.getMethod("test", String.class, CompletionHandler.class);
|
||||
Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType);
|
||||
Type resultType = null;
|
||||
if (handlerType instanceof Class) {
|
||||
resultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
resultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
}
|
||||
if (!main) {
|
||||
Assertions.assertEquals(resultType, File.class);
|
||||
}
|
||||
System.out.println("resultType = " + resultType);
|
||||
}
|
||||
|
||||
public static abstract class Service1 {
|
||||
|
||||
public abstract void test(String name, CompletionHandler<String, Integer> handler);
|
||||
}
|
||||
|
||||
public static abstract class IService2<T> {
|
||||
|
||||
public abstract void test(String name, CompletionHandler<T, Integer> handler);
|
||||
}
|
||||
|
||||
public static abstract class Service2 extends IService2<File> {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user