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 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); * *