From 707fc783b5e9c3505f20033197fa74eb902e7774 Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Thu, 25 Aug 2016 08:52:18 +0800 Subject: [PATCH] --- .../redkale/net/http/BasedHttpServlet.java | 356 +---------------- src/org/redkale/net/http/HttpBaseServlet.java | 366 ++++++++++++++++++ .../redkale/net/http/HttpPrepareServlet.java | 8 +- src/org/redkale/net/http/RestHttpServlet.java | 2 +- src/org/redkale/net/http/RestService.java | 2 +- .../redkale/net/http/RestServletBuilder.java | 4 +- 6 files changed, 378 insertions(+), 360 deletions(-) create mode 100644 src/org/redkale/net/http/HttpBaseServlet.java diff --git a/src/org/redkale/net/http/BasedHttpServlet.java b/src/org/redkale/net/http/BasedHttpServlet.java index 97d1baf33..376579a8a 100644 --- a/src/org/redkale/net/http/BasedHttpServlet.java +++ b/src/org/redkale/net/http/BasedHttpServlet.java @@ -5,362 +5,14 @@ */ package org.redkale.net.http; -import org.redkale.net.Response; -import org.redkale.net.Request; -import org.redkale.util.AnyValue; -import java.io.IOException; -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.reflect.Method; -import java.nio.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.*; -import jdk.internal.org.objectweb.asm.*; -import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; -import static jdk.internal.org.objectweb.asm.Opcodes.*; -import org.redkale.service.RetResult; - /** * *

* 详情见: http://redkale.org + * + * @deprecated 使用 org.redkale.net.http.HttpBaseServlet 代替 * * @author zhangjx */ -public abstract class BasedHttpServlet extends HttpServlet { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - public static final int RET_SERVER_ERROR = 1800_0001; - - public static final int RET_METHOD_ERROR = 1800_0002; - - /** - * 配合 BasedHttpServlet 使用。 - * 当标记为 @AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。 - * - *

- * 详情见: http://redkale.org - * - * @author zhangjx - */ - @Inherited - @Documented - @Target({METHOD, TYPE}) - @Retention(RUNTIME) - protected @interface AuthIgnore { - - } - - /** - * 配合 BasedHttpServlet 使用。 - * 用于对@WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀, 且不能是正则表达式 - * - *

- * 详情见: http://redkale.org - * - * @author zhangjx - */ - @Target({ElementType.METHOD}) - @Retention(RetentionPolicy.RUNTIME) - @Documented - protected @interface WebAction { - - int actionid() default 0; - - String url(); - - String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法 - } - - /** - * 配合 BasedHttpServlet 使用。 - * 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一定时间(默认值timeout=15秒)。 - * 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,因为没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。 - * - *

- * 详情见: http://redkale.org - * - * @author zhangjx - */ - @Target({ElementType.METHOD}) - @Retention(RetentionPolicy.RUNTIME) - @Documented - protected @interface HttpCacheable { - - /** - * 超时的秒数 - * - * @return 超时秒数 - */ - int timeout() default 15; - } - - private Map.Entry[] actions; - - /** - * 异常输出 - * - * @param req HTTP请求对象 - * @param resp HTTP响应对象 - * @param exp 异常 - */ - protected void sendExceptionResult(HttpRequest req, HttpResponse resp, Throwable exp) { - logger.log(Level.SEVERE, "request = " + req, exp); - resp.finishJson(new RetResult(RET_SERVER_ERROR, "Server Error")); - } - - public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException { - return true; - } - - @Override - public final void execute(HttpRequest request, HttpResponse response) throws IOException { - if (!preExecute(request, response)) return; - for (Map.Entry en : actions) { - if (request.getRequestURI().startsWith(en.getKey())) { - Entry entry = en.getValue(); - if (!entry.checkMethod(request.getMethod())) { - response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); - return; - } - if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) { - if (entry.cachetimeout > 0) {//有缓存设置 - CacheEntry ce = entry.cache.get(request.getRequestURI()); - if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效 - response.setStatus(ce.status); - response.setContentType(ce.contentType); - response.finish(ce.getBuffers()); - return; - } - response.setBufferHandler(entry.cacheHandler); - } - entry.servlet.execute(request, response); - } - return; - } - } - throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")"); - } - - public final void preInit(HttpContext context, AnyValue config) { - String path = _prefix == null ? "" : _prefix; - WebServlet ws = this.getClass().getAnnotation(WebServlet.class); - if (ws != null && !ws.repair()) path = ""; - HashMap map = load(); - this.actions = new Map.Entry[map.size()]; - int i = -1; - for (Map.Entry en : map.entrySet()) { - actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue()); - } - //必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query - Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey())); - } - - public final void postDestroy(HttpContext context, AnyValue config) { - } - - public abstract boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException; - - private HashMap load() { - final boolean typeIgnore = this.getClass().getAnnotation(AuthIgnore.class) != null; - WebServlet module = this.getClass().getAnnotation(WebServlet.class); - final int serviceid = module == null ? 0 : module.moduleid(); - final HashMap map = new HashMap<>(); - Set nameset = new HashSet<>(); - for (final Method method : this.getClass().getMethods()) { - //----------------------------------------------- - String methodname = method.getName(); - if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue; - //----------------------------------------------- - Class[] paramTypes = method.getParameterTypes(); - if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class - || paramTypes[1] != HttpResponse.class) continue; - //----------------------------------------------- - Class[] exps = method.getExceptionTypes(); - if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue; - //----------------------------------------------- - - final WebAction action = method.getAnnotation(WebAction.class); - if (action == null) continue; - final int actionid = action.actionid(); - final String name = action.url().trim(); - - if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")"); - //屏蔽以下代码,允许相互包含 -// for (String n : nameset) { -// if (n.contains(name) || name.contains(n)) { -// throw new RuntimeException(this.getClass().getSimpleName() + " has two sub-contains " + WebAction.class.getSimpleName() + "(" + name + ", " + n + ")"); -// } -// } - nameset.add(name); - map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method))); - } - return map; - } - - private HttpServlet createHttpServlet(final Method method) { - //------------------------------------------------------------------------------ - final String supDynName = HttpServlet.class.getName().replace('.', '/'); - final String interName = this.getClass().getName().replace('.', '/'); - final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass()); - final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class); - final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class); - final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class); - final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class); - String newDynName = interName + "_Dyn_" + method.getName(); - int i = 0; - for (;;) { - try { - Class.forName(newDynName.replace('/', '.')); - newDynName += "_" + (++i); - } catch (Exception ex) { - break; - } - } - //------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - final String factfield = "_factServlet"; - cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); - { - fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null); - fv.visitEnd(); - } - { //构造函数 - mv = (cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - //mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"})); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"}); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/')); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/')); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw.visitEnd(); - //------------------------------------------------------------------------------ - byte[] bytes = cw.toByteArray(); - Class newClazz = new ClassLoader(this.getClass().getClassLoader()) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - try { - HttpServlet instance = (HttpServlet) newClazz.newInstance(); - instance.getClass().getField(factfield).set(instance, this); - return instance; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - private static final class Entry { - - public Entry(boolean typeIgnore, int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) { - this.moduleid = moduleid; - this.actionid = actionid; - this.name = name; - this.methods = methods; - this.method = method; - this.servlet = servlet; - this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null; - HttpCacheable hc = method.getAnnotation(HttpCacheable.class); - this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000; - this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null; - this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> { - int status = response.getStatus(); - if (status != 200) return null; - CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers); - cache.put(response.getRequest().getRequestURI(), ce); - return ce.getBuffers(); - } : null; - } - - public boolean isNeedCheck() { - return this.moduleid != 0 || this.actionid != 0; - } - - public boolean checkMethod(final String reqMethod) { - if (methods.length == 0) return true; - for (String m : methods) { - if (reqMethod.equalsIgnoreCase(m)) return true; - } - return false; - } - - public final HttpResponse.BufferHandler cacheHandler; - - public final ConcurrentHashMap cache; - - public final int cachetimeout; - - public final boolean ignore; - - public final int moduleid; - - public final int actionid; - - public final String name; - - public final String[] methods; - - public final Method method; - - public final HttpServlet servlet; - } - - private static final class CacheEntry { - - public final long time = System.currentTimeMillis(); - - private final ByteBuffer[] buffers; - - private final int status; - - private final String contentType; - - public CacheEntry(int status, String contentType, ByteBuffer[] bufs) { - this.status = status; - this.contentType = contentType; - final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length]; - for (int i = 0; i < newBuffers.length; i++) { - newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer(); - } - this.buffers = newBuffers; - } - - public ByteBuffer[] getBuffers() { - final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length]; - for (int i = 0; i < newBuffers.length; i++) { - newBuffers[i] = buffers[i].duplicate(); - } - return newBuffers; - } - } -} +public abstract class BasedHttpServlet extends HttpBaseServlet { +} \ No newline at end of file diff --git a/src/org/redkale/net/http/HttpBaseServlet.java b/src/org/redkale/net/http/HttpBaseServlet.java new file mode 100644 index 000000000..ca89ec0bd --- /dev/null +++ b/src/org/redkale/net/http/HttpBaseServlet.java @@ -0,0 +1,366 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import org.redkale.net.Response; +import org.redkale.net.Request; +import org.redkale.util.AnyValue; +import java.io.IOException; +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.reflect.Method; +import java.nio.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.*; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import org.redkale.service.RetResult; + +/** + * + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ +public abstract class HttpBaseServlet extends HttpServlet { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + public static final int RET_SERVER_ERROR = 1800_0001; + + public static final int RET_METHOD_ERROR = 1800_0002; + + /** + * 配合 HttpBaseServlet 使用。 + * 当标记为 @AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。 + * + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ + @Inherited + @Documented + @Target({METHOD, TYPE}) + @Retention(RUNTIME) + protected @interface AuthIgnore { + + } + + /** + * 配合 HttpBaseServlet 使用。 + * 用于对@WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀, 且不能是正则表达式 + * + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + @Documented + protected @interface WebAction { + + int actionid() default 0; + + String url(); + + String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法 + } + + /** + * 配合 HttpBaseServlet 使用。 + * 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一定时间(默认值timeout=15秒)。 + * 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,因为没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。 + * + *

+ * 详情见: http://redkale.org + * + * @author zhangjx + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + @Documented + protected @interface HttpCacheable { + + /** + * 超时的秒数 + * + * @return 超时秒数 + */ + int timeout() default 15; + } + + private Map.Entry[] actions; + + /** + * 异常输出 + * + * @param req HTTP请求对象 + * @param resp HTTP响应对象 + * @param exp 异常 + */ + protected void sendExceptionResult(HttpRequest req, HttpResponse resp, Throwable exp) { + logger.log(Level.SEVERE, "request = " + req, exp); + resp.finishJson(new RetResult(RET_SERVER_ERROR, "Server Error")); + } + + public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException { + return true; + } + + @Override + public final void execute(HttpRequest request, HttpResponse response) throws IOException { + if (!preExecute(request, response)) return; + for (Map.Entry en : actions) { + if (request.getRequestURI().startsWith(en.getKey())) { + Entry entry = en.getValue(); + if (!entry.checkMethod(request.getMethod())) { + response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); + return; + } + if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) { + if (entry.cachetimeout > 0) {//有缓存设置 + CacheEntry ce = entry.cache.get(request.getRequestURI()); + if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效 + response.setStatus(ce.status); + response.setContentType(ce.contentType); + response.finish(ce.getBuffers()); + return; + } + response.setBufferHandler(entry.cacheHandler); + } + entry.servlet.execute(request, response); + } + return; + } + } + throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")"); + } + + public final void preInit(HttpContext context, AnyValue config) { + String path = _prefix == null ? "" : _prefix; + WebServlet ws = this.getClass().getAnnotation(WebServlet.class); + if (ws != null && !ws.repair()) path = ""; + HashMap map = load(); + this.actions = new Map.Entry[map.size()]; + int i = -1; + for (Map.Entry en : map.entrySet()) { + actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue()); + } + //必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query + Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey())); + } + + public final void postDestroy(HttpContext context, AnyValue config) { + } + + public abstract boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException; + + private HashMap load() { + final boolean typeIgnore = this.getClass().getAnnotation(AuthIgnore.class) != null; + WebServlet module = this.getClass().getAnnotation(WebServlet.class); + final int serviceid = module == null ? 0 : module.moduleid(); + final HashMap map = new HashMap<>(); + Set nameset = new HashSet<>(); + for (final Method method : this.getClass().getMethods()) { + //----------------------------------------------- + String methodname = method.getName(); + if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue; + //----------------------------------------------- + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class + || paramTypes[1] != HttpResponse.class) continue; + //----------------------------------------------- + Class[] exps = method.getExceptionTypes(); + if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue; + //----------------------------------------------- + + final WebAction action = method.getAnnotation(WebAction.class); + if (action == null) continue; + final int actionid = action.actionid(); + final String name = action.url().trim(); + + if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")"); + //屏蔽以下代码,允许相互包含 +// for (String n : nameset) { +// if (n.contains(name) || name.contains(n)) { +// throw new RuntimeException(this.getClass().getSimpleName() + " has two sub-contains " + WebAction.class.getSimpleName() + "(" + name + ", " + n + ")"); +// } +// } + nameset.add(name); + map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method))); + } + return map; + } + + private HttpServlet createHttpServlet(final Method method) { + //------------------------------------------------------------------------------ + final String supDynName = HttpServlet.class.getName().replace('.', '/'); + final String interName = this.getClass().getName().replace('.', '/'); + final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass()); + final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class); + final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class); + final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class); + final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class); + String newDynName = interName + "_Dyn_" + method.getName(); + int i = 0; + for (;;) { + try { + Class.forName(newDynName.replace('/', '.')); + newDynName += "_" + (++i); + } catch (Exception ex) { + break; + } + } + //------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + final String factfield = "_factServlet"; + cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); + { + fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null); + fv.visitEnd(); + } + { //构造函数 + mv = (cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + //mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"})); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"}); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/')); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/')); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + //------------------------------------------------------------------------------ + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader(this.getClass().getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + try { + HttpServlet instance = (HttpServlet) newClazz.newInstance(); + instance.getClass().getField(factfield).set(instance, this); + return instance; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static final class Entry { + + public Entry(boolean typeIgnore, int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) { + this.moduleid = moduleid; + this.actionid = actionid; + this.name = name; + this.methods = methods; + this.method = method; + this.servlet = servlet; + this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null; + HttpCacheable hc = method.getAnnotation(HttpCacheable.class); + this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000; + this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null; + this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> { + int status = response.getStatus(); + if (status != 200) return null; + CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers); + cache.put(response.getRequest().getRequestURI(), ce); + return ce.getBuffers(); + } : null; + } + + public boolean isNeedCheck() { + return this.moduleid != 0 || this.actionid != 0; + } + + public boolean checkMethod(final String reqMethod) { + if (methods.length == 0) return true; + for (String m : methods) { + if (reqMethod.equalsIgnoreCase(m)) return true; + } + return false; + } + + public final HttpResponse.BufferHandler cacheHandler; + + public final ConcurrentHashMap cache; + + public final int cachetimeout; + + public final boolean ignore; + + public final int moduleid; + + public final int actionid; + + public final String name; + + public final String[] methods; + + public final Method method; + + public final HttpServlet servlet; + } + + private static final class CacheEntry { + + public final long time = System.currentTimeMillis(); + + private final ByteBuffer[] buffers; + + private final int status; + + private final String contentType; + + public CacheEntry(int status, String contentType, ByteBuffer[] bufs) { + this.status = status; + this.contentType = contentType; + final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length]; + for (int i = 0; i < newBuffers.length; i++) { + newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer(); + } + this.buffers = newBuffers; + } + + public ByteBuffer[] getBuffers() { + final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length]; + for (int i = 0; i < newBuffers.length; i++) { + newBuffers[i] = buffers[i].duplicate(); + } + return newBuffers; + } + } +} diff --git a/src/org/redkale/net/http/HttpPrepareServlet.java b/src/org/redkale/net/http/HttpPrepareServlet.java index 12dd5d480..45640f5cd 100644 --- a/src/org/redkale/net/http/HttpPrepareServlet.java +++ b/src/org/redkale/net/http/HttpPrepareServlet.java @@ -36,8 +36,8 @@ public final class HttpPrepareServlet extends PrepareServlet { if (s instanceof WebSocketServlet) { ((WebSocketServlet) s).preInit(context, getServletConf(s)); - } else if (s instanceof BasedHttpServlet) { - ((BasedHttpServlet) s).preInit(context, getServletConf(s)); + } else if (s instanceof HttpBaseServlet) { + ((HttpBaseServlet) s).preInit(context, getServletConf(s)); } s.init(context, getServletConf(s)); }); @@ -165,8 +165,8 @@ public final class HttpPrepareServlet extends PrepareServlet */ -public abstract class RestHttpServlet extends BasedHttpServlet { +public abstract class RestHttpServlet extends HttpBaseServlet { protected abstract T currentUser(HttpRequest req) throws IOException; diff --git a/src/org/redkale/net/http/RestService.java b/src/org/redkale/net/http/RestService.java index 92b502f16..d5f10c351 100644 --- a/src/org/redkale/net/http/RestService.java +++ b/src/org/redkale/net/http/RestService.java @@ -29,6 +29,6 @@ public @interface RestService { boolean repair() default true; //同@WebServlet的repair属性 - int module() default 0; //模块ID值,鉴权时用到, 对应@WebServlet.ignore + int module() default 0; //模块ID值,鉴权时用到, 对应@WebServlet.module } diff --git a/src/org/redkale/net/http/RestServletBuilder.java b/src/org/redkale/net/http/RestServletBuilder.java index 6f88e9567..37e0f5f0d 100644 --- a/src/org/redkale/net/http/RestServletBuilder.java +++ b/src/org/redkale/net/http/RestServletBuilder.java @@ -49,8 +49,8 @@ public final class RestServletBuilder { final String webServletDesc = Type.getDescriptor(WebServlet.class); final String httpRequestDesc = Type.getDescriptor(HttpRequest.class); final String httpResponseDesc = Type.getDescriptor(HttpResponse.class); - final String authDesc = Type.getDescriptor(BasedHttpServlet.AuthIgnore.class); - final String actionDesc = Type.getDescriptor(BasedHttpServlet.WebAction.class); + final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class); + final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class); final String serviceTypeString = serviceType.getName().replace('.', '/'); final Class userType = getSuperUserType(baseServletClass);