This commit is contained in:
@@ -130,6 +130,39 @@ public abstract class Sncp {
|
||||
}
|
||||
}
|
||||
|
||||
static void checkAsyncModifier(Class param, Method method) {
|
||||
if (param == AsyncHandler.class) return;
|
||||
if (Modifier.isFinal(param.getModifiers())) {
|
||||
throw new RuntimeException("AsyncHandler Type Parameter on {" + method + "} cannot final modifier");
|
||||
}
|
||||
if (!Modifier.isPublic(param.getModifiers())) {
|
||||
throw new RuntimeException("AsyncHandler Type Parameter on {" + method + "} must be public modifier");
|
||||
}
|
||||
if (param.isInterface()) return;
|
||||
boolean constructorflag = false;
|
||||
for (Constructor c : param.getDeclaredConstructors()) {
|
||||
if (c.getParameterCount() == 0) {
|
||||
int mod = c.getModifiers();
|
||||
if (Modifier.isPublic(mod) || Modifier.isProtected(mod)) {
|
||||
constructorflag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (constructorflag) throw new RuntimeException(param + " must have a empty parameter Constructor");
|
||||
for (Method m : param.getMethods()) {
|
||||
if (m.getName().equals("completed") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new RuntimeException(param + "'s completed method cannot final modifier");
|
||||
} else if (m.getName().equals("failed") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new RuntimeException(param + "'s failed method cannot final modifier");
|
||||
} else if (m.getName().equals("sncp_getParams") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new RuntimeException(param + "'s sncp_getParams method cannot final modifier");
|
||||
} else if (m.getName().equals("sncp_setParams") && Modifier.isFinal(m.getModifiers())) {
|
||||
throw new RuntimeException(param + "'s sncp_setParams method cannot final modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* public class TestService implements Service{
|
||||
@@ -139,16 +172,16 @@ public abstract class Sncp {
|
||||
* }
|
||||
*
|
||||
* @RpcMultiRun(selfrun = false)
|
||||
public void createSomeThing(TestBean bean){
|
||||
//do something
|
||||
}
|
||||
|
||||
@RpcMultiRun
|
||||
public String updateSomeThing(String id){
|
||||
return "hello" + id;
|
||||
}
|
||||
}
|
||||
</pre></blockquote>
|
||||
* public void createSomeThing(TestBean bean){
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* @RpcMultiRun
|
||||
* public String updateSomeThing(String id){
|
||||
* return "hello" + id;
|
||||
* }
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Resource(name = "")
|
||||
@@ -362,7 +395,13 @@ public abstract class Sncp {
|
||||
mv.visitInsn(mrun.samerun() ? ICONST_1 : ICONST_0);
|
||||
mv.visitInsn(mrun.diffrun() ? ICONST_1 : ICONST_0);
|
||||
int varindex = 0;
|
||||
boolean handlerFuncFlag = false;
|
||||
for (Class pt : paramtypes) {
|
||||
if (AsyncHandler.class.isAssignableFrom(pt)) {
|
||||
if (handlerFuncFlag) throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
|
||||
checkAsyncModifier(pt, method);
|
||||
handlerFuncFlag = true;
|
||||
}
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, ++varindex);
|
||||
@@ -403,8 +442,15 @@ public abstract class Sncp {
|
||||
//mv.setDebug(true);
|
||||
{ //给参数加上 Annotation
|
||||
final Annotation[][] anns = method.getParameterAnnotations();
|
||||
boolean handlerAttachFlag = false;
|
||||
for (int k = 0; k < anns.length; k++) {
|
||||
for (Annotation ann : anns[k]) {
|
||||
if (ann.annotationType() == RpcAttachment.class) {
|
||||
if (handlerAttachFlag) {
|
||||
throw new RuntimeException(method + " have more than one @RpcAttachment parameter");
|
||||
}
|
||||
handlerAttachFlag = true;
|
||||
}
|
||||
if (ann instanceof SncpDyn || ann instanceof RpcMultiRun) continue; //必须过滤掉 RpcMultiRun、SncpDyn,否则生成远程模式Service时会出错
|
||||
visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.sncp.SncpDynServlet.SncpServletAction;
|
||||
import org.redkale.util.AsyncHandler;
|
||||
|
||||
/**
|
||||
* 异步回调函数
|
||||
* 异步回调函数 <br>
|
||||
*
|
||||
* public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
@@ -18,17 +23,123 @@ import org.redkale.util.AsyncHandler;
|
||||
* @param <V> 结果对象的泛型
|
||||
* @param <A> 附件对象的泛型
|
||||
*/
|
||||
public abstract class SncpAsyncHandler<V, A> implements AsyncHandler<V, A> {
|
||||
public interface SncpAsyncHandler<V, A> extends AsyncHandler<V, A> {
|
||||
|
||||
//为了在回调函数中调用_callParameter方法
|
||||
protected Object[] params;
|
||||
public Object[] sncp_getParams();
|
||||
|
||||
public Object[] getParams() {
|
||||
return params;
|
||||
public void sncp_setParams(Object... params);
|
||||
|
||||
static class Factory {
|
||||
|
||||
/**
|
||||
* <blockquote><pre>
|
||||
* 若参数类型为AsyncHandler子类,必须保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
|
||||
* 考虑点:
|
||||
* 1、AsyncHandler子类是接口,且还有其他多个方法
|
||||
* 2、AsyncHandler子类是类, 需要继承,且必须有空参数构造函数
|
||||
* 3、AsyncHandler子类无论是接口还是类,都可能存在其他泛型
|
||||
*
|
||||
* public class _DyncSncpAsyncHandler_xxx extends XXXAsyncHandler implements SncpAsyncHandler {
|
||||
*
|
||||
* public SncpAsyncHandler handler;
|
||||
*
|
||||
* protected Object[] params;
|
||||
*
|
||||
* @Override
|
||||
* public void completed(Object result, Object attachment) {
|
||||
* handler.completed(result, attachment);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, Object attachment) {
|
||||
* handler.failed(exc, attachment);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public Object[] sncp_getParams() {
|
||||
* return params;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void sncp_setParams(Object... params) {
|
||||
* this.params = params;
|
||||
* handler.sncp_setParams(params);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param <V> 结果对象的泛型
|
||||
* @param <A> 附件对象的泛型
|
||||
* @param handlerClass AsyncHandler类型或子类
|
||||
* @param action SncpServletAction
|
||||
* @param in BsonReader
|
||||
* @param out BsonWriter
|
||||
* @param request SncpRequest
|
||||
* @param response SncpResponse
|
||||
*
|
||||
* @return SncpAsyncHandler
|
||||
*/
|
||||
public static <V, A> SncpAsyncHandler<V, A> create(Class<? extends AsyncHandler> handlerClass, SncpServletAction action,
|
||||
BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) {
|
||||
if (handlerClass == AsyncHandler.class) return new DefaultSncpAsyncHandler(action, in, out, request, response);
|
||||
//子类, 待实现
|
||||
return new DefaultSncpAsyncHandler(action, in, out, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public void setParams(Object... params) {
|
||||
this.params = params;
|
||||
}
|
||||
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;
|
||||
|
||||
public DefaultSncpAsyncHandler(SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ public final class SncpClient {
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(params[i], method);
|
||||
handlerFuncIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -120,29 +120,11 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
BsonWriter out = action.convert.pollBsonWriter(bufferSupplier);
|
||||
out.writeTo(DEFAULT_HEADER);
|
||||
BsonReader in = action.convert.pollBsonReader();
|
||||
SncpAsyncHandler handler;
|
||||
SncpAsyncHandler handler = null;
|
||||
try {
|
||||
handler = action.handlerFuncParamIndex >= 0 ? new SncpAsyncHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
try {
|
||||
action._callParameter(out, params);
|
||||
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);
|
||||
}
|
||||
} : null;
|
||||
if (action.handlerFuncParamIndex >= 0) {
|
||||
handler = SncpAsyncHandler.Factory.create(action.handlerFuncParamClass, action, in, out, request, response);
|
||||
}
|
||||
in.setBytes(request.getBody());
|
||||
action.action(in, out, handler);
|
||||
if (handler == null) {
|
||||
@@ -170,6 +152,8 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
|
||||
protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在AsyncHandler参数
|
||||
|
||||
protected Class handlerFuncParamClass; //AsyncHandler参数的类型
|
||||
|
||||
public abstract void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable;
|
||||
|
||||
public final void _callParameter(final BsonWriter out, final Object... params) {
|
||||
@@ -226,9 +210,9 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* handler.setParams(arg0, arg1, arg2, arg3);
|
||||
* handler.sncp_setParams(arg0, arg1, arg2, arg3);
|
||||
* service.insert(arg0, arg1, arg2, arg3);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_update extends SncpServletAction {
|
||||
@@ -244,11 +228,11 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* handler.setParams(a1, a2, a3, arg1, arg2, arg3);
|
||||
* handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
|
||||
* service.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param service Service
|
||||
@@ -307,6 +291,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
throw new RuntimeException(ex); //不可能会发生
|
||||
}
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncClass = null;
|
||||
{ // action方法
|
||||
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"}));
|
||||
//mv.setDebug(true);
|
||||
@@ -320,8 +305,11 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(paramClasses[i], method);
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncClass = paramClasses[i];
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
codes[i] = new int[]{ALOAD, store};
|
||||
store++;
|
||||
@@ -421,7 +409,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, handlerName, "setParams", "([Ljava/lang/Object;)V", false);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
|
||||
}
|
||||
{ //调用service
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
@@ -527,6 +515,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
System.arraycopy(ptypes, 0, types, 1, ptypes.length);
|
||||
instance.paramTypes = types;
|
||||
instance.handlerFuncParamIndex = handlerFuncIndex;
|
||||
instance.handlerFuncParamClass = handlerFuncClass;
|
||||
|
||||
org.redkale.util.Attribute[] atts = new org.redkale.util.Attribute[ptypes.length + 1];
|
||||
Annotation[][] anns = method.getParameterAnnotations();
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.redkale.util.*;
|
||||
* Service编写异步方法:
|
||||
* 1、异步方法有且仅有一个类型为AsyncHandler的参数。
|
||||
* 2、异步方法返回类型必须是void。
|
||||
* 例如:
|
||||
* 例如:
|
||||
* public void insertRecord(AsyncHandler<Integer, Record> handler, String name, @RpcAttachment Record record);
|
||||
*
|
||||
* </pre></blockquote>
|
||||
|
||||
Reference in New Issue
Block a user