This commit is contained in:
Redkale
2017-03-22 10:31:14 +08:00
parent 0bd0df3245
commit 19a44ce8cf
5 changed files with 195 additions and 48 deletions

View File

@@ -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 {
* }
*
* &#64;RpcMultiRun(selfrun = false)
public void createSomeThing(TestBean bean){
//do something
}
&#64;RpcMultiRun
public String updateSomeThing(String id){
return "hello" + id;
}
}
</pre></blockquote>
* public void createSomeThing(TestBean bean){
* //do something
* }
*
* &#64;RpcMultiRun
* public String updateSomeThing(String id){
* return "hello" + id;
* }
* }
* </pre></blockquote>
*
* <blockquote><pre>
* &#64;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);
}

View File

@@ -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;
*
* &#64;Override
* public void completed(Object result, Object attachment) {
* handler.completed(result, attachment);
* }
*
* &#64;Override
* public void failed(Throwable exc, Object attachment) {
* handler.failed(exc, attachment);
* }
*
* &#64;Override
* public Object[] sncp_getParams() {
* return params;
* }
*
* &#64;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;
}
}
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -24,7 +24,7 @@ import org.redkale.util.*;
* Service编写异步方法
* 1、异步方法有且仅有一个类型为AsyncHandler的参数。
* 2、异步方法返回类型必须是void。
* 例如:
* 例如:
* public void insertRecord(AsyncHandler&#60;Integer, Record&#62; handler, String name, &#64;RpcAttachment Record record);
*
* </pre></blockquote>