diff --git a/src/org/redkale/net/sncp/Sncp.java b/src/org/redkale/net/sncp/Sncp.java index cf30dd4b8..1191e1a0b 100644 --- a/src/org/redkale/net/sncp/Sncp.java +++ b/src/org/redkale/net/sncp/Sncp.java @@ -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"); + } + } + } + /** *
* 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;
- }
- }
-
+ * public void createSomeThing(TestBean bean){
+ * //do something
+ * }
+ *
+ * @RpcMultiRun
+ * public String updateSomeThing(String id){
+ * return "hello" + id;
+ * }
+ * }
+ *
*
*
* @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);
}
diff --git a/src/org/redkale/net/sncp/SncpAsyncHandler.java b/src/org/redkale/net/sncp/SncpAsyncHandler.java
index 3d5d2012e..10eb80711 100644
--- a/src/org/redkale/net/sncp/SncpAsyncHandler.java
+++ b/src/org/redkale/net/sncp/SncpAsyncHandler.java
@@ -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;
/**
- * 异步回调函数
+ * 异步回调函数
+ *
+ * public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler
*
*
*
@@ -18,17 +23,123 @@ import org.redkale.util.AsyncHandler;
* @param 结果对象的泛型
* @param 附件对象的泛型
*/
-public abstract class SncpAsyncHandler implements AsyncHandler {
+public interface SncpAsyncHandler extends AsyncHandler {
- //为了在回调函数中调用_callParameter方法
- protected Object[] params;
+ public Object[] sncp_getParams();
- public Object[] getParams() {
- return params;
+ public void sncp_setParams(Object... params);
+
+ static class Factory {
+
+ /**
+ *
+ * 若参数类型为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);
+ * }
+ * }
+ *
+ *
+ *
+ * @param 结果对象的泛型
+ * @param 附件对象的泛型
+ * @param handlerClass AsyncHandler类型或子类
+ * @param action SncpServletAction
+ * @param in BsonReader
+ * @param out BsonWriter
+ * @param request SncpRequest
+ * @param response SncpResponse
+ *
+ * @return SncpAsyncHandler
+ */
+ public static SncpAsyncHandler 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 implements SncpAsyncHandler {
+ //为了在回调函数中调用_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;
+ }
+
+ }
}
diff --git a/src/org/redkale/net/sncp/SncpClient.java b/src/org/redkale/net/sncp/SncpClient.java
index 8345db22c..f7aaa808e 100644
--- a/src/org/redkale/net/sncp/SncpClient.java
+++ b/src/org/redkale/net/sncp/SncpClient.java
@@ -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;
}
diff --git a/src/org/redkale/net/sncp/SncpDynServlet.java b/src/org/redkale/net/sncp/SncpDynServlet.java
index 74b23852f..79e64a315 100644
--- a/src/org/redkale/net/sncp/SncpDynServlet.java
+++ b/src/org/redkale/net/sncp/SncpDynServlet.java
@@ -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);
- * }
+ * }
* }
- *
+ *
*
*
* @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();
diff --git a/src/org/redkale/service/Service.java b/src/org/redkale/service/Service.java
index d381afb17..831a1bc8a 100644
--- a/src/org/redkale/service/Service.java
+++ b/src/org/redkale/service/Service.java
@@ -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);
*
*