From 74f554fe3363e8ee0fa222eeb31afc44f0253e4b Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Thu, 25 May 2017 15:57:18 +0800 Subject: [PATCH] --- conf/logging.properties | 1 + src/META-INF/logging-template.properties | 2 +- src/org/redkale/net/http/Rest.java | 157 ++++++++++++++---- .../wsdync/_DyncChatWebSocketServlet.java | 12 +- 4 files changed, 138 insertions(+), 34 deletions(-) diff --git a/conf/logging.properties b/conf/logging.properties index 1c3c7dc65..de5bfb95c 100644 --- a/conf/logging.properties +++ b/conf/logging.properties @@ -18,6 +18,7 @@ java.util.logging.FileHandler.limit = 10485760 java.util.logging.FileHandler.count = 10000 java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log +java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%u.log java.util.logging.FileHandler.append = true java.util.logging.ConsoleHandler.level = FINE diff --git a/src/META-INF/logging-template.properties b/src/META-INF/logging-template.properties index 80570c360..72730937b 100644 --- a/src/META-INF/logging-template.properties +++ b/src/META-INF/logging-template.properties @@ -17,7 +17,7 @@ java.util.logging.FileHandler.count = 100 java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%u.log #java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d -java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/warnerr-log-%u.log +java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%u.log java.util.logging.FileHandler.append = true #java.util.logging.ConsoleHandler.level = FINE diff --git a/src/org/redkale/net/http/Rest.java b/src/org/redkale/net/http/Rest.java index ac88dd707..7a2190b92 100644 --- a/src/org/redkale/net/http/Rest.java +++ b/src/org/redkale/net/http/Rest.java @@ -136,8 +136,8 @@ public final class Rest { resourcesFieldSet.add(field); } } while ((clzz = clzz.getSuperclass()) != Object.class); - final List resourcesFields = new ArrayList<>(resourcesFieldSet); + final List resourcesFields = new ArrayList<>(resourcesFieldSet); StringBuilder sb1 = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); for (int i = 0; i < resourcesFields.size(); i++) { @@ -151,6 +151,7 @@ public final class Rest { //---------------------------------------------------------------------------------------- final Map> asmParamMap = MethodParamClassVisitor.getMethodParamNames(webSocketType); final Set messageNames = new HashSet<>(); + final List messageMethods = new ArrayList<>(); for (Method method : webSocketType.getMethods()) { RestOnMessage rom = method.getAnnotation(RestOnMessage.class); if (rom == null) continue; @@ -158,6 +159,7 @@ public final class Rest { if (name.isEmpty()) throw new RuntimeException(method + " RestOnMessage.name is empty createRestWebSocketServlet"); if (messageNames.contains(name)) throw new RuntimeException(method + " repeat RestOnMessage.name(" + name + ") createRestWebSocketServlet"); messageNames.add(name); + messageMethods.add(method); } //---------------------------------------------------------------------------------------- @@ -167,12 +169,14 @@ public final class Rest { final String newDynName = webSocketInternalName.substring(0, webSocketInternalName.lastIndexOf('/') + 1) + "_Dyn" + webSocketType.getSimpleName() + "Servlet"; - final String newWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName(); - final String newDynWebSokcetFullName = newDynName + "$" + newWebSokcetSimpleName; + final String newDynWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName(); + final String newDynWebSokcetFullName = newDynName + "$" + newDynWebSokcetSimpleName; - final String newMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message"; - final String newMessageFullName = newDynName + "$" + newMessageSimpleName; + final String newDynMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message"; + final String newDynMessageFullName = newDynName + "$" + newDynMessageSimpleName; + final String newDynConsumerSimpleName = "_DynRestOnMessageConsumer"; + final String newDynConsumerFullName = newDynName + "$" + newDynConsumerSimpleName; //---------------------------------------------------------------------------------------- ClassLoader loader = Rest.class.getClassLoader(); @@ -196,14 +200,17 @@ public final class Rest { av0.visitEnd(); } { //内部类 - cw.visitInnerClass(newDynName + "$RestOnMessageConsumer", newDynName, "RestOnMessageConsumer", ACC_PUBLIC + ACC_STATIC); + cw.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC); - cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); + cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); - cw.visitInnerClass(newMessageFullName, newDynName, newMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + cw.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); - //cw.visitInnerClass("org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage_joinroom", newDynName, "_DyncChatWebSocketMessage_joinroom", ACC_PUBLIC + ACC_STATIC); - //cw.visitInnerClass("org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage_sendmessagee", newDynName, "_DyncChatWebSocketMessage_sendmessagee", ACC_PUBLIC + ACC_STATIC); + for (int i = 0; i < messageMethods.size(); i++) { + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + cw.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); + } } {//@Resource for (int i = 0; i < resourcesFields.size(); i++) { @@ -224,7 +231,7 @@ public final class Rest { mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newWebSokcetSimpleName + "Message")); + mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newDynWebSokcetSimpleName + "Message")); mv.visitFieldInsn(PUTFIELD, newDynName, "messageTextType", "Ljava/lang/reflect/Type;"); mv.visitInsn(RETURN); mv.visitMaxs(2, 1); @@ -232,13 +239,13 @@ public final class Rest { } { //createWebSocket 方法 mv = new AsmMethodVisitor(cw.visitMethod(ACC_PROTECTED, "createWebSocket", "()Lorg/redkale/net/http/WebSocket;", "()Lorg/redkale/net/http/WebSocket;", null)); - mv.visitTypeInsn(NEW, newDynName + "$" + newWebSokcetSimpleName); + mv.visitTypeInsn(NEW, newDynName + "$" + newDynWebSokcetSimpleName); mv.visitInsn(DUP); for (int i = 0; i < resourcesFields.size(); i++) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_resource_" + i, Type.getDescriptor(resourcesFields.get(i).getType())); } - mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + newWebSokcetSimpleName, "", "(" + resourceDescriptor + ")V", false); + mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + newDynWebSokcetSimpleName, "", "(" + resourceDescriptor + ")V", false); mv.visitInsn(ARETURN); mv.visitMaxs(2 + resourcesFields.size(), 1); mv.visitEnd(); @@ -246,11 +253,76 @@ public final class Rest { cw.visitEnd(); RestClassLoader newLoader = new RestClassLoader(loader); - { //_DyncXXXWebSocket class + for (int i = 0; i < messageMethods.size(); i++) { // _DyncXXXWebSocketMessage List + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName + endfix, null, "java/lang/Object", null); + + cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); + Set paramnames = new HashSet<>(); + String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method); + List names = asmParamMap.get(methodesc); + Parameter[] params = method.getParameters(); + for (int j = 0; j < params.length; j++) { + Parameter param = params[j]; + String paramname = param.getName(); + RestParam rp = param.getAnnotation(RestParam.class); + if (rp != null && !rp.name().isEmpty()) { + paramname = rp.name(); + } else if (names != null && names.size() > j) { + paramname = names.get(j); + } + if (paramnames.contains(paramname)) throw new RuntimeException(method + " has same @RestParam.name"); + paramnames.add(paramname); + fv = cw2.visitField(ACC_PUBLIC, paramname, Type.getDescriptor(param.getType()), + param.getType() == param.getParameterizedType() ? null : Utility.getTypeDescriptor(param.getParameterizedType()), null); + fv.visitEnd(); + } + { //构造函数 + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw2.visitEnd(); + newLoader.loadClass(newDynMessageFullName.replace('/', '.'), cw2.toByteArray()); + } + + { //_DynXXXWebSocketMessage class + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName, null, "java/lang/Object", null); + + cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + + for (int i = 0; i < messageMethods.size(); i++) { + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); + } + + { + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "", "(" + resourceDescriptor + ")V", resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw2.visitEnd(); + newLoader.loadClass(newDynMessageFullName.replace('/', '.'), cw2.toByteArray()); + } + + { //_DynXXXWebSocket class ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynWebSokcetFullName, null, webSocketInternalName, null); - cw2.visitInnerClass(newDynWebSokcetFullName, newDynName, newWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); + cw2.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); { mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "", "(" + resourceDescriptor + ")V", resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), null)); @@ -270,24 +342,56 @@ public final class Rest { newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), cw2.toByteArray()); } - { //_DyncXXXWebSocketMessage class + { //_DynRestOnMessageConsumer class ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newMessageFullName, null, "java/lang/Object", null); + cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynConsumerFullName, "Ljava/lang/Object;Ljava/util/function/BiConsumer;", "java/lang/Object", new String[]{"java/util/function/BiConsumer"}); - cw2.visitInnerClass(newMessageFullName, newDynName, newMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + cw2.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC); + cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + for (int i = 0; i < messageMethods.size(); i++) { + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); + } - { - mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "", "(" + resourceDescriptor + ")V", resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "", "()V", false); + { //构造函数 + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } + + { //accept函数 + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "accept", "(Lorg/redkale/net/http/WebSocket;Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, newDynWebSokcetFullName); + mv.visitVarInsn(ASTORE, 3); + + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, newDynMessageFullName); + mv.visitVarInsn(ASTORE, 4); + + //待开发 + + mv.visitMaxs(3, 5); + mv.visitEnd(); + } + {//虚拟accept函数 + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, "org/redkale/net/http/WebSocket"); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynConsumerFullName, "accept", "(Lorg/redkale/net/http/WebSocket;Ljava/lang/Object;)V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } cw2.visitEnd(); - newLoader.loadClass(newMessageFullName.replace('/', '.'), cw2.toByteArray()); + newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), cw2.toByteArray()); } Class newClazz = newLoader.loadClass(newDynName.replace('/', '.'), cw.toByteArray()); @@ -1324,12 +1428,7 @@ public final class Rest { } cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); + Class newClazz = new RestClassLoader(loader).loadClass(newDynName.replace('/', '.'), cw.toByteArray()); try { T obj = ((Class) newClazz).newInstance(); for (Map.Entry en : restAttributes.entrySet()) { diff --git a/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java b/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java index 80564f12d..1b1d0c2e8 100644 --- a/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java +++ b/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java @@ -34,8 +34,9 @@ public final class _DyncChatWebSocketServlet extends WebSocketServlet { return (WebSocket) new _DyncChatWebSocket(service); } + @Override protected BiConsumer createRestOnMessageConsumer() { - return new RestOnMessageConsumer(); + return new _DynRestOnMessageConsumer(); } public static class _DyncChatWebSocket extends ChatWebSocket { @@ -68,16 +69,19 @@ public final class _DyncChatWebSocketServlet extends WebSocketServlet { } - public static class RestOnMessageConsumer implements BiConsumer { + public static class _DynRestOnMessageConsumer implements BiConsumer { @Override public void accept(WebSocket websocket0, Object message0) { - ChatWebSocket websocket = (ChatWebSocket) websocket0; + _DyncChatWebSocket websocket = (_DyncChatWebSocket) websocket0; _DyncChatWebSocketMessage message = (_DyncChatWebSocketMessage) message0; if (message.sendmessage != null) { websocket.onChatMessage(message.sendmessage.message, message.sendmessage.extmap); - } else if (message.sendmessage != null) { + return; + } + if (message.joinroom != null) { websocket.onJoinRoom(message.joinroom.roomid); + return; } }